package depends.extractor.cpp.cdt; import depends.entity.GenericName; import depends.entity.TypeEntity; import org.eclipse.cdt.core.dom.ast.*; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTemplateId; import org.eclipse.cdt.internal.core.model.ASTStringUtil; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * This extends the CDT ASTStringUtil class. * A tricky point here is that we have to use some of the reflection mechanism to invoke * some private functions in ASTStringUtils class * It is not good, but it seems the most easiest one to reuse existing functions */ public class ASTStringUtilExt extends ASTStringUtil { public static String getName(IASTDeclSpecifier decl) { StringBuilder buffer = new StringBuilder(); String name = appendBareDeclSpecifierString(buffer, decl).toString().replace("::", ".").replace("...", ""); return name; } public static String getName(IASTLiteralExpression expr) { return expr.getRawSignature().replace("::", ".").replace("...", ""); } public static String getTypeIdString(IASTTypeId typeId) { StringBuilder sb = new StringBuilder(); return appendBareTypeIdString(sb, typeId).toString().replace("::", "."); } /** * retrieve template parameters from declSpecifier */ public static List getTemplateParameters(IASTDeclSpecifier declSpecifier) { List parameters = new ArrayList<>(); declSpecifier.accept(new TemplateParameterASTVisitor(parameters)); return parameters; } private static StringBuilder appendBareDeclSpecifierString(StringBuilder buffer, IASTDeclSpecifier declSpecifier) { if (declSpecifier instanceof IASTCompositeTypeSpecifier) { final IASTCompositeTypeSpecifier compositeTypeSpec = (IASTCompositeTypeSpecifier) declSpecifier; appendBareNameString(buffer, compositeTypeSpec.getName()); } else if (declSpecifier instanceof IASTElaboratedTypeSpecifier) { final IASTElaboratedTypeSpecifier elaboratedTypeSpec = (IASTElaboratedTypeSpecifier) declSpecifier; appendBareNameString(buffer, elaboratedTypeSpec.getName()); } else if (declSpecifier instanceof IASTEnumerationSpecifier) { final IASTEnumerationSpecifier enumerationSpec = (IASTEnumerationSpecifier) declSpecifier; appendBareNameString(buffer, enumerationSpec.getName()); } else if (declSpecifier instanceof IASTSimpleDeclSpecifier) { buffer.append(TypeEntity.buildInType.getRawName()); } else if (declSpecifier instanceof IASTNamedTypeSpecifier) { final IASTNamedTypeSpecifier namedTypeSpec = (IASTNamedTypeSpecifier) declSpecifier; appendBareNameString(buffer, namedTypeSpec.getName()); } return buffer; } private static StringBuilder appendBareNameString(StringBuilder buffer, IASTName name) { if (name instanceof ICPPASTQualifiedName) { final ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) name; final ICPPASTNameSpecifier[] segments = qualifiedName.getAllSegments(); for (int i = 0; i < segments.length; i++) { if (i > 0) { buffer.append("."); } appendQualifiedNameStringWithReflection(buffer, segments[i]); } } else if (name instanceof CPPASTTemplateId) { appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)name); } else if (name != null) { buffer.append(name.getSimpleID()); } return buffer; } private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, IASTName name) { try { Method m = ASTStringUtil.class.getDeclaredMethod("appendQualifiedNameString", StringBuilder.class, IASTName.class); m.setAccessible(true); // if security settings allow this m.invoke(null, buffer, name); // use null if the method is static } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.err.println("Error: cannot invoke ASTStringUtils method of "); } } private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, CPPASTTemplateId templateId) { appendQualifiedNameStringWithReflection(buffer,templateId.getTemplateName()); } private static void appendQualifiedNameStringWithReflection(StringBuilder buffer, ICPPASTNameSpecifier nameSpecifier) { if (nameSpecifier instanceof CPPASTTemplateId) { appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)nameSpecifier); return; } try { Method m = ASTStringUtil.class.getDeclaredMethod("appendQualifiedNameString", StringBuilder.class, ICPPASTNameSpecifier.class); m.setAccessible(true); // if security settings allow this m.invoke(null, buffer, nameSpecifier); // use null if the method is static } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.err.println("Error: cannot invoke ASTStringUtils method of "); } } private static StringBuilder appendBareTypeIdString(StringBuilder buffer, IASTTypeId typeId) { return appendBareDeclSpecifierString(buffer, typeId.getDeclSpecifier()); } public static String getName(IASTDeclarator declarator) { return declarator.getName().toString().replace("::", "."); } public static String getName(ICPPASTUsingDeclaration declaration) { return declaration.getName().toString().replace("::", "."); } public static String getName(IASTName name) { return name.getRawSignature().toString().replace("::", "."); } private static StringBuilder appendBareNameString(StringBuilder buffer, ICPPASTNameSpecifier name) { if (name instanceof ICPPASTQualifiedName) { final ICPPASTQualifiedName qualifiedName = (ICPPASTQualifiedName) name; final ICPPASTNameSpecifier[] segments = qualifiedName.getAllSegments(); for (int i = 0; i < segments.length; i++) { if (i > 0) { buffer.append("."); } appendQualifiedNameStringWithReflection(buffer, segments[i]); } } else if (name instanceof CPPASTTemplateId) { appendQualifiedNameStringWithReflection(buffer,(CPPASTTemplateId)name); } else if (name != null) { buffer.append(name.getRawSignature()); } return buffer; } public static String getName(ICPPASTNameSpecifier nameSpecifier) { StringBuilder buffer = new StringBuilder(); String name = appendBareNameString(buffer, nameSpecifier).toString().replace("::", ".").replace("...", ""); return name; } }