All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.psr.vulas.java.sign.UniqueNameNormalizer Maven / Gradle / Ivy

There is a newer version: 3.1.15
Show newest version
/**
 * This file is part of Eclipse Steady.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.
 */
package com.sap.psr.vulas.java.sign;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sap.psr.vulas.ConstructId;
import com.sap.psr.vulas.core.util.SignatureConfiguration;
import com.sap.psr.vulas.shared.util.VulasConfiguration;

import ch.uzh.ifi.seal.changedistiller.model.classifiers.EntityType;
import ch.uzh.ifi.seal.changedistiller.model.entities.IUniqueNameNormalizer;
import ch.uzh.ifi.seal.changedistiller.model.entities.SourceCodeEntity;

/**
 * 

UniqueNameNormalizer class.

* */ public class UniqueNameNormalizer implements IUniqueNameNormalizer { private static final Log log = LogFactory.getLog(UniqueNameNormalizer.class); private static final Pattern CONSTANT_PATTERN = Pattern.compile("([0-9a-zA-Z_\\.]+)\\.([0-9A-Z_]+)"); private static UniqueNameNormalizer instance = null; private ClassLoader classLoader = null; private static String cua = null; // class under analysis private UniqueNameNormalizer() {} /** *

Getter for the field instance.

* * @return a {@link com.sap.psr.vulas.java.sign.UniqueNameNormalizer} object. */ public static synchronized UniqueNameNormalizer getInstance() { if(instance==null) instance = new UniqueNameNormalizer(); return instance; } /** * Fully qualified class names to be searched for class names found in strings. */ private final Set classNames = new HashSet(); /** *

addStrings.

* * @param _class_names a {@link java.util.Collection} object. */ public final void addStrings(Collection _class_names) { classNames.addAll(_class_names); } /** *

addStrings.

* * @param _class_names an array of {@link java.lang.String} objects. */ public final void addStrings(String[] _class_names) { classNames.addAll(Arrays.asList(_class_names)); } /** *

addConstructIds.

* * @param _classes a {@link java.util.Collection} object. */ public final void addConstructIds(Collection _classes) { for(ConstructId cid: _classes) { classNames.add(cid.getQualifiedName()); } } /** * Sets the class loader used for inlining constants, see {@link UniqueNameNormalizer#findConstants(String, String)}. * * @param _cl a {@link java.lang.ClassLoader} object. */ public void setClassLoader(ClassLoader _cl) { this.classLoader = _cl; } /** {@inheritDoc} */ @Override public boolean haveEqualUniqueName(SourceCodeEntity _e1, SourceCodeEntity _e2) { // Equality before normalization final boolean eq_before_norm = _e1.getUniqueName().equals(_e2.getUniqueName()); // Equality after normalization final String p1 = this.normalizeUniqueName(_e1); final String p2 = this.normalizeUniqueName(_e2); final boolean eq_after_norm = p1.equals(p2); // Print log message in case the pre-processing realized a match that did not exist before if(!eq_before_norm && eq_after_norm) { // && !_e1.equals(_e2)) { UniqueNameNormalizer.log.info("Preprocessor match: Old [" + _e1 + "] and [" + _e2 + "]"); UniqueNameNormalizer.log.info(" New [" + p1 + "] and [" + p2 + "]"); } return eq_after_norm; } /** * Applies changes that are independent of a given {@link EntityType} to the given {@link String}. * In more detail, the string is trimmed, occurrences of "this." are removed and constants are inlined. * * @param _string a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String normalizeUniqueName(String _string) { String tmp = _string.trim(); tmp = tmp.replaceAll("this\\.", ""); tmp = tmp.replaceAll("(Object)", ""); if( VulasConfiguration.getGlobal().getConfiguration().getBoolean(SignatureConfiguration.RELAX_STRIP_FINALS) ) { tmp = tmp.replaceAll("final ", ""); } //TODO: Replace single characters 'x' by ASCII codes (cf. CVE-2009-2625) as done by some compilers tmp = this.inlineConstants(tmp); return tmp; } /** * {@inheritDoc} * * Applies changes to the unique name of the given {@link SourceCodeEntity}, potentially dependent * on its specific {@link EntityType}. */ @Override public String normalizeUniqueName(SourceCodeEntity _entity) { String toFix = _entity.getUniqueName(); // get rid of class name for static methods if ( _entity.getType().isStatement() && cua != null ){ toFix = removeLeadingClassName(toFix); } // Normalizations applicable to all entities String tmp = this.normalizeUniqueName(toFix); tmp = this.removeNumberCasts(tmp); // Normalizations specific to entity types // Variable declaration: Remove leading "final" return tmp; } /** *

removeLeadingClassName.

* * @param _string a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String removeLeadingClassName(String _string ){ String tmp = _string.trim(); tmp = tmp.replaceAll(cua+"\\.", ""); return tmp; } /** *

removeNumberCasts.

* * @param _string a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String removeNumberCasts(String _string){ String regex_string = "[^\"]*\"[^\"]*\""; Pattern pattern_string = Pattern.compile(regex_string); Matcher matcher_string = pattern_string.matcher(_string); // do not substitute when is a user defined string if ( ! matcher_string.matches() ) { String regex = "([^0-9]*)([0-9]+)([BDFL])(.*)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(_string); String tmp = ""; int i =0; while ( matcher.find() ){ String tmp2 = matcher.group(1); tmp2 += matcher.group(2); tmp2 += matcher.group(4); tmp+=tmp2; i = matcher.end(); } return tmp; } else { return _string; } } /** *

inlineConstants.

* * @param _string a {@link java.lang.String} object. * @return a {@link java.lang.String} object. */ public String inlineConstants(String _string) { final StringBuilder b = new StringBuilder(); final Matcher m = CONSTANT_PATTERN.matcher(_string); int idx = 0; String constant_name = null, constant_value = null; Set fields = null; while(m.find()) { constant_name = _string.substring(m.start(), m.end()); // Find fields and take value fields = this.findConstants(m.group(1), m.group(2)); if(fields.size()==1) constant_value = this.getConstantValue(fields.iterator().next()); else if(fields.size()>1) { UniqueNameNormalizer.log.warn(fields.size() + " constants [" + constant_name + "] found, take first"); constant_value = this.getConstantValue(fields.iterator().next()); } else constant_value = null; b.append(_string.substring(idx, m.start())); if(constant_value==null) b.append(_string.substring(m.start(), m.end())); else b.append(constant_value); idx = m.end(); } b.append(_string.substring(idx)); return b.toString(); } /** * Returns the value of the given {@link Field} as {@link String}. * * Todo: Until now, the method only distinguishes primitive types and * everything else. In both cases, the value is obtained by calling * toString. In the latter case, the value is additionally wrapped in quotes. * One must probably distinguish further cases, e.g., chars wrapper by single quotes. * * @param _field * @return */ private String getConstantValue(Field _field) { final StringBuilder value = new StringBuilder(); try { final Class type = _field.getType(); _field.setAccessible(true); if(type.isPrimitive()) { value.append(_field.get(null).toString()); } else { value.append("\"").append(_field.get(null).toString()).append("\""); } } catch (IllegalArgumentException e) { UniqueNameNormalizer.log.error("Error while obtaining value of field [" + _field + "]: " + e.getMessage(), e); } catch (IllegalAccessException e) { UniqueNameNormalizer.log.error("Error while accessing value of field [" + _field + "]: " + e.getMessage(), e); } catch (NoClassDefFoundError e2) {} return value.toString(); } /** * Searches for classes or interfaces of the given name (w/o package qualifier) and which have a constant of the given name. * * Considers all classes before passed to {@link UniqueNameNormalizer#addStrings(Collection)} or the other two methods. * At the same time, the classes must be in the class path so that they can be loaded. * * @param _class_name * @param _field_name * @return */ private Set findConstants(String _class_name, String _field_name) { // Find all classes final Set classes = new HashSet(); // Replace . in class names by $ final String class_name = _class_name.replaceAll("\\.", "\\$"); Class cl = null; for(String qn : this.classNames) { if(qn.indexOf(class_name)!=-1) { // If existing, try the member class loader (e.g., set by the Maven plugin) if(this.classLoader!=null) { try { cl = this.classLoader.loadClass(qn); } catch(ClassNotFoundException e) {} catch (NoClassDefFoundError e2){} } // If not existing or unsuccessful, try the system class loader if(cl==null) { try { cl = Class.forName(qn); } catch(ClassNotFoundException e) {} catch( NoClassDefFoundError e2) {} } // Add if found, otherwise write error message if(cl==null) UniqueNameNormalizer.log.error("Error instantiating class or interface [" + qn + "], needed for constant [" + _class_name + "." + _field_name + "]"); else classes.add(cl); } } // For each class, try to find a constant with the given name final Set fields = new HashSet(); Field f = null; int mod = -1; for(Class c: classes) { try { f = c.getDeclaredField(_field_name); mod = f.getModifiers(); if(Modifier.isStatic(mod) && Modifier.isFinal(mod)) { fields.add(f); } } catch (NoSuchFieldException e) {} catch (NoClassDefFoundError e) { UniqueNameNormalizer.log.error("Class definition not found when searching for constant [" + _field_name + "] in class or interface [" + c.getName() + "]: " + e.getMessage()); } catch (SecurityException e) { UniqueNameNormalizer.log.error("Security exception when searching for constant [" + _field_name + "] in class or interface [" + c.getName() + "]: " + e.getMessage(), e); } } return fields; } /** *

setClassUnderAnalysisName.

* * @param _name a {@link java.lang.String} object. */ public void setClassUnderAnalysisName(String _name){ cua = _name; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy