| /******************************************************************************* |
| * Copyright (c) 2006, 2014 Wind River Systems, Inc. and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Anton Leherbauer (Wind River Systems) - initial API and implementation |
| * Markus Schorn (Wind River Systems) |
| *******************************************************************************/ |
| package org.eclipse.cdt.internal.core.model; |
| |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.eclipse.cdt.core.CCorePlugin; |
| import org.eclipse.cdt.core.dom.ast.DOMException; |
| import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTElaboratedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; |
| import org.eclipse.cdt.core.dom.ast.IASTExpression; |
| import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFileLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTName; |
| import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTNode; |
| import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorFunctionStyleMacroDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; |
| import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; |
| import org.eclipse.cdt.core.dom.ast.IASTProblem; |
| import org.eclipse.cdt.core.dom.ast.IASTProblemDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; |
| import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; |
| import org.eclipse.cdt.core.dom.ast.IBinding; |
| import org.eclipse.cdt.core.dom.ast.IScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExplicitTemplateInstantiation; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNameSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceAlias; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStaticAssertDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateSpecialization; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeTransformationSpecifier; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; |
| import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; |
| import org.eclipse.cdt.core.index.IIndex; |
| import org.eclipse.cdt.core.index.IIndexManager; |
| import org.eclipse.cdt.core.model.CModelException; |
| import org.eclipse.cdt.core.model.ICElement; |
| import org.eclipse.cdt.core.model.IContributedModelBuilder; |
| import org.eclipse.cdt.core.model.INamespace; |
| import org.eclipse.cdt.core.model.IProblemRequestor; |
| import org.eclipse.cdt.core.model.ISourceReference; |
| import org.eclipse.cdt.core.model.IStructure; |
| import org.eclipse.cdt.core.model.ITranslationUnit; |
| import org.eclipse.cdt.core.parser.Keywords; |
| import org.eclipse.cdt.core.parser.ParseError; |
| import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; |
| import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; |
| import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| |
| /** |
| * Build TranslationUnit structure from an {@code IASTTranslationUnit}. |
| * |
| * @since 4.0 |
| */ |
| public class CModelBuilder2 implements IContributedModelBuilder { |
| private final static boolean DEBUG = Util.isActive(DebugLogConstants.MODEL); |
| |
| private final TranslationUnit fTranslationUnit; |
| private final Map<ICElement, CElementInfo> fNewElements; |
| private final IProgressMonitor fProgressMonitor; |
| |
| private ASTAccessVisibility fCurrentVisibility; |
| private Stack<ASTAccessVisibility> fVisibilityStack; |
| private HashMap<ISourceReference, int[]> fEqualElements; |
| |
| /** |
| * Create a model builder for the given translation unit. |
| * |
| * @param tu the translation unit (must be a {@link TranslationUnit} |
| * @param newElements element cache |
| * @param monitor the progress monitor |
| */ |
| public CModelBuilder2(ITranslationUnit tu, Map<ICElement, CElementInfo> newElements, IProgressMonitor monitor) { |
| fTranslationUnit = (TranslationUnit) tu; |
| fNewElements = newElements; |
| fProgressMonitor = monitor; |
| } |
| |
| @Override |
| public void parse(boolean quickParseMode) throws Exception { |
| final IIndexManager indexManager = CCorePlugin.getIndexManager(); |
| IIndex index = indexManager.getIndex(fTranslationUnit.getCProject(), |
| IIndexManager.ADD_EXTENSION_FRAGMENTS_EDITOR); |
| |
| try { |
| if (index != null) { |
| try { |
| index.acquireReadLock(); |
| } catch (InterruptedException e) { |
| index = null; |
| } |
| } |
| checkCanceled(); |
| long startTime = System.currentTimeMillis(); |
| final CElementInfo elementInfo = getElementInfo(fTranslationUnit); |
| int parseFlags = quickParseMode ? ITranslationUnit.AST_SKIP_ALL_HEADERS |
| : ITranslationUnit.AST_SKIP_INDEXED_HEADERS; |
| if (!(elementInfo instanceof ASTHolderTUInfo)) { |
| parseFlags |= ITranslationUnit.AST_SKIP_FUNCTION_BODIES; |
| } else { |
| parseFlags |= ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT; |
| } |
| parseFlags |= ITranslationUnit.AST_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS; |
| parseFlags |= ITranslationUnit.AST_PARSE_INACTIVE_CODE; |
| final IASTTranslationUnit ast; |
| try { |
| ast = fTranslationUnit.getAST(index, parseFlags, fProgressMonitor); |
| if (DEBUG) { |
| Util.debugLog("CModelBuilder2: parsing " //$NON-NLS-1$ |
| + fTranslationUnit.getElementName() + " mode=" //$NON-NLS-1$ |
| + (quickParseMode ? "skip all " : "skip indexed ") //$NON-NLS-1$ //$NON-NLS-2$ |
| + " time=" + (System.currentTimeMillis() - startTime) + "ms", //$NON-NLS-1$ //$NON-NLS-2$ |
| DebugLogConstants.MODEL, false); |
| } |
| } catch (ParseError e) { |
| checkCanceled(); |
| throw e; |
| } |
| if (ast == null) { |
| return; |
| } |
| |
| checkCanceled(); |
| startTime = System.currentTimeMillis(); |
| buildModel(ast); |
| elementInfo.setIsStructureKnown(true); |
| if (DEBUG) { |
| Util.debugLog("CModelBuilder2: building " //$NON-NLS-1$ |
| + "children=" + elementInfo.internalGetChildren().size() //$NON-NLS-1$ |
| + " time=" + (System.currentTimeMillis() - startTime) + "ms", //$NON-NLS-1$ //$NON-NLS-2$ |
| DebugLogConstants.MODEL, false); |
| } |
| |
| if (elementInfo instanceof ASTHolderTUInfo) { |
| ((ASTHolderTUInfo) elementInfo).fAST = ast; |
| // preserve index lock for AST receiver |
| index = null; |
| } |
| } finally { |
| if (index != null) { |
| index.releaseReadLock(); |
| } |
| } |
| } |
| |
| private boolean isCanceled() { |
| return fProgressMonitor != null && fProgressMonitor.isCanceled(); |
| } |
| |
| private void checkCanceled() { |
| if (fProgressMonitor != null && fProgressMonitor.isCanceled()) { |
| if (DEBUG) |
| Util.debugLog("CModelBuilder2: cancelled ", DebugLogConstants.MODEL, false); //$NON-NLS-1$ |
| throw new OperationCanceledException(); |
| } |
| } |
| |
| /** |
| * Build the model from the given AST. |
| * @param ast |
| * @throws CModelException |
| * @throws DOMException |
| */ |
| private void buildModel(IASTTranslationUnit ast) throws CModelException, DOMException { |
| fVisibilityStack = new Stack<>(); |
| fEqualElements = new HashMap<>(); |
| |
| // includes |
| final IASTPreprocessorIncludeStatement[] includeDirectives = ast.getIncludeDirectives(); |
| for (IASTPreprocessorIncludeStatement includeDirective : includeDirectives) { |
| if (isLocalToFile(includeDirective)) { |
| createInclusion(fTranslationUnit, includeDirective); |
| } |
| } |
| // Macros |
| final IASTPreprocessorMacroDefinition[] macroDefinitions = ast.getMacroDefinitions(); |
| for (IASTPreprocessorMacroDefinition macroDefinition : macroDefinitions) { |
| if (isLocalToFile(macroDefinition)) { |
| createMacro(fTranslationUnit, macroDefinition); |
| } |
| } |
| // Declarations |
| final IASTDeclaration[] declarations = ast.getDeclarations(true); |
| for (IASTDeclaration declaration : declarations) { |
| if (isLocalToFile(declaration)) { |
| createDeclaration(fTranslationUnit, declaration); |
| } |
| } |
| fEqualElements.clear(); |
| |
| // Sort by offset |
| final List<ICElement> children = getElementInfo(fTranslationUnit).internalGetChildren(); |
| Collections.sort(children, new Comparator<ICElement>() { |
| @Override |
| public int compare(ICElement o1, ICElement o2) { |
| final SourceManipulationInfo info1 = getSourceManipulationInfo((SourceManipulation) o1); |
| final SourceManipulationInfo info2 = getSourceManipulationInfo((SourceManipulation) o2); |
| int delta = info1.getStartPos() - info2.getStartPos(); |
| if (delta == 0) { |
| delta = info1.getIdStartPos() - info2.getIdStartPos(); |
| } |
| return delta; |
| } |
| }); |
| |
| if (isCanceled()) { |
| return; |
| } |
| |
| // Report problems |
| IProblemRequestor problemRequestor = fTranslationUnit.getProblemRequestor(); |
| if (problemRequestor != null && problemRequestor.isActive()) { |
| problemRequestor.beginReporting(); |
| final IASTProblem[] ppProblems = ast.getPreprocessorProblems(); |
| IASTProblem[] problems = ppProblems; |
| for (IASTProblem problem : problems) { |
| if (isLocalToFile(problem)) { |
| problemRequestor.acceptProblem(problem); |
| } |
| } |
| problems = CPPVisitor.getProblems(ast); |
| for (IASTProblem problem : problems) { |
| if (isLocalToFile(problem)) { |
| problemRequestor.acceptProblem(problem); |
| } |
| } |
| problemRequestor.endReporting(); |
| } |
| } |
| |
| private boolean isLocalToFile(IASTNode node) { |
| return node.isPartOfTranslationUnitFile(); |
| } |
| |
| private Include createInclusion(Parent parent, IASTPreprocessorIncludeStatement inclusion) throws CModelException { |
| // Create element |
| final IASTName name = inclusion.getName(); |
| Include element = new Include(parent, ASTStringUtil.getSimpleName(name), inclusion.isSystemInclude()); |
| element.setFullPathName(inclusion.getPath()); |
| setIndex(element); |
| |
| element.setActive(inclusion.isActive()); |
| element.setResolved(inclusion.isResolved()); |
| // Add to parent |
| parent.addChild(element); |
| // Set positions |
| setIdentifierPosition(element, name); |
| setBodyPosition(element, inclusion); |
| return element; |
| } |
| |
| private void setIndex(SourceManipulation element) { |
| int[] idx = fEqualElements.get(element); |
| if (idx == null) { |
| idx = new int[] { 0 }; |
| fEqualElements.put(element, idx); |
| } else { |
| element.setIndex(++idx[0]); |
| } |
| } |
| |
| private Macro createMacro(Parent parent, IASTPreprocessorMacroDefinition macro) throws CModelException { |
| // Create element |
| final IASTName name = macro.getName(); |
| Macro element = new Macro(parent, ASTStringUtil.getSimpleName(name)); |
| setIndex(element); |
| element.setActive(macro.isActive()); |
| // Add to parent |
| parent.addChild(element); |
| // Set positions |
| setIdentifierPosition(element, name); |
| setBodyPosition(element, macro); |
| if (macro instanceof IASTPreprocessorFunctionStyleMacroDefinition) { |
| element.setFunctionStyle(true); |
| } |
| return element; |
| } |
| |
| private void createDeclaration(Parent parent, IASTDeclaration declaration) throws CModelException, DOMException { |
| if (declaration instanceof IASTFunctionDefinition) { |
| createFunctionDefinition(parent, (IASTFunctionDefinition) declaration, false); |
| } else if (declaration instanceof IASTSimpleDeclaration) { |
| createSimpleDeclarations(parent, (IASTSimpleDeclaration) declaration, false); |
| } else if (declaration instanceof ICPPASTVisibilityLabel) { |
| handleVisibilityLabel((ICPPASTVisibilityLabel) declaration); |
| } else if (declaration instanceof ICPPASTNamespaceDefinition) { |
| createNamespace(parent, (ICPPASTNamespaceDefinition) declaration); |
| } else if (declaration instanceof ICPPASTNamespaceAlias) { |
| // TODO [cmodel] namespace alias? |
| } else if (declaration instanceof ICPPASTTemplateDeclaration) { |
| createTemplateDeclaration(parent, (ICPPASTTemplateDeclaration) declaration); |
| } else if (declaration instanceof ICPPASTTemplateSpecialization) { |
| // TODO [cmodel] template specialization? |
| } else if (declaration instanceof ICPPASTExplicitTemplateInstantiation) { |
| // TODO [cmodel] explicit template instantiation? |
| } else if (declaration instanceof ICPPASTAliasDeclaration) { |
| // TODO [cmodel] alias declaration? |
| } else if (declaration instanceof ICPPASTUsingDeclaration) { |
| createUsingDeclaration(parent, (ICPPASTUsingDeclaration) declaration); |
| } else if (declaration instanceof ICPPASTUsingDirective) { |
| createUsingDirective(parent, (ICPPASTUsingDirective) declaration); |
| } else if (declaration instanceof ICPPASTLinkageSpecification) { |
| createLinkageSpecification(parent, (ICPPASTLinkageSpecification) declaration); |
| } else if (declaration instanceof IASTASMDeclaration) { |
| // TODO [cmodel] asm declaration? |
| } else if (declaration instanceof IASTProblemDeclaration) { |
| // TODO [cmodel] problem declaration? |
| } else if (declaration instanceof ICPPASTStaticAssertDeclaration) { |
| // ignore |
| } else { |
| assert false : "TODO: " + declaration.getClass().getName(); //$NON-NLS-1$ |
| } |
| } |
| |
| private void createTemplateDeclaration(Parent parent, ICPPASTTemplateDeclaration templateDeclaration) |
| throws CModelException, DOMException { |
| IASTDeclaration declaration = templateDeclaration.getDeclaration(); |
| if (declaration instanceof IASTFunctionDefinition) { |
| CElement element = createFunctionDefinition(parent, (IASTFunctionDefinition) declaration, true); |
| String[] parameterTypes = ASTStringUtil |
| .getTemplateParameterArray(templateDeclaration.getTemplateParameters()); |
| // set the template parameters |
| if (element instanceof FunctionTemplate) { |
| FunctionTemplate functionTemplate = (FunctionTemplate) element; |
| functionTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof MethodTemplate) { |
| MethodTemplate methodTemplate = (MethodTemplate) element; |
| methodTemplate.setTemplateParameterTypes(parameterTypes); |
| } |
| // set the body position |
| if (element instanceof SourceManipulation) { |
| setBodyPosition((SourceManipulation) element, templateDeclaration); |
| } |
| } else if (declaration instanceof IASTSimpleDeclaration) { |
| CElement[] elements = createSimpleDeclarations(parent, (IASTSimpleDeclaration) declaration, true); |
| String[] parameterTypes = ASTStringUtil |
| .getTemplateParameterArray(templateDeclaration.getTemplateParameters()); |
| for (CElement element : elements) { |
| // set the template parameters |
| if (element instanceof StructureTemplate) { |
| StructureTemplate classTemplate = (StructureTemplate) element; |
| classTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof StructureTemplateDeclaration) { |
| StructureTemplateDeclaration classTemplate = (StructureTemplateDeclaration) element; |
| classTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof VariableTemplate) { |
| VariableTemplate varTemplate = (VariableTemplate) element; |
| varTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof FunctionTemplateDeclaration) { |
| FunctionTemplateDeclaration functionTemplate = (FunctionTemplateDeclaration) element; |
| functionTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof MethodTemplateDeclaration) { |
| MethodTemplateDeclaration methodTemplate = (MethodTemplateDeclaration) element; |
| methodTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof FunctionTemplate) { |
| FunctionTemplate functionTemplate = (FunctionTemplate) element; |
| functionTemplate.setTemplateParameterTypes(parameterTypes); |
| } else if (element instanceof MethodTemplate) { |
| MethodTemplate methodTemplate = (MethodTemplate) element; |
| methodTemplate.setTemplateParameterTypes(parameterTypes); |
| } |
| // set the body position |
| if (element instanceof SourceManipulation) { |
| setBodyPosition((SourceManipulation) element, templateDeclaration); |
| } |
| } |
| } else if (declaration instanceof ICPPASTAliasDeclaration) { |
| createDeclaration(parent, declaration); |
| } else if (declaration instanceof ICPPASTTemplateDeclaration) { |
| // strange: template decl inside template decl |
| createTemplateDeclaration(parent, (ICPPASTTemplateDeclaration) declaration); |
| } else if (declaration instanceof IASTProblemDeclaration) { |
| // ignore problem declarations (or create special elements for debugging?) |
| } else { |
| assert false : "TODO: " + declaration.getClass().getName(); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Handle extern "C" and related kinds. |
| * |
| * @param parent |
| * @param declaration |
| * @throws CModelException |
| * @throws DOMException |
| */ |
| private void createLinkageSpecification(Parent parent, ICPPASTLinkageSpecification linkageDeclaration) |
| throws CModelException, DOMException { |
| IASTDeclaration[] declarations = linkageDeclaration.getDeclarations(true); |
| for (IASTDeclaration declaration : declarations) { |
| if (linkageDeclaration.getFileLocation() != null || isLocalToFile(declaration)) { |
| createDeclaration(parent, declaration); |
| } |
| } |
| } |
| |
| private CElement[] createSimpleDeclarations(Parent parent, IASTSimpleDeclaration declaration, boolean isTemplate) |
| throws CModelException, DOMException { |
| final IASTDeclSpecifier declSpecifier = declaration.getDeclSpecifier(); |
| final IASTDeclarator[] declarators = declaration.getDeclarators(); |
| final CElement[] elements; |
| boolean isCompositeType = declSpecifier instanceof IASTCompositeTypeSpecifier |
| || declSpecifier instanceof IASTEnumerationSpecifier; |
| if (declarators.length == 0) { |
| elements = new CElement[1]; |
| final CElement element = createSimpleDeclaration(parent, declSpecifier, null, isTemplate); |
| elements[0] = element; |
| } else { |
| if (isCompositeType) { |
| createSimpleDeclaration(parent, declSpecifier, null, isTemplate); |
| } |
| elements = new CElement[declarators.length]; |
| for (int i = 0; i < declarators.length; i++) { |
| final IASTDeclarator declarator = declarators[i]; |
| final CElement element = createSimpleDeclaration(parent, declSpecifier, declarator, isTemplate); |
| if (!isTemplate && element instanceof SourceManipulation && declarators.length > 1) { |
| setBodyPosition((SourceManipulation) element, declarator); |
| } |
| elements[i] = element; |
| } |
| } |
| return elements; |
| } |
| |
| private CElement createSimpleDeclaration(Parent parent, IASTDeclSpecifier declSpecifier, IASTDeclarator declarator, |
| boolean isTemplate) throws CModelException, DOMException { |
| if (declSpecifier instanceof IASTCompositeTypeSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| return createCompositeType(parent, (IASTCompositeTypeSpecifier) declSpecifier, isTemplate); |
| } else if (declSpecifier instanceof IASTElaboratedTypeSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| return createElaboratedTypeDeclaration(parent, (IASTElaboratedTypeSpecifier) declSpecifier, isTemplate); |
| } else if (declSpecifier instanceof IASTEnumerationSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| return createEnumeration(parent, (IASTEnumerationSpecifier) declSpecifier); |
| } else if (declSpecifier instanceof IASTNamedTypeSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| } else if (declSpecifier instanceof IASTSimpleDeclSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| } else if (declSpecifier instanceof ICPPASTTypeTransformationSpecifier) { |
| if (declarator != null) { |
| return createTypedefOrFunctionOrVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| } else { |
| assert false : "TODO: " + declSpecifier.getClass().getName(); //$NON-NLS-1$ |
| } |
| return null; |
| } |
| |
| private CElement createTypedefOrFunctionOrVariable(Parent parent, IASTDeclSpecifier declSpecifier, |
| IASTDeclarator declarator, boolean isTemplate) throws CModelException { |
| assert declarator != null; |
| if (declSpecifier.getStorageClass() == IASTDeclSpecifier.sc_typedef) { |
| return createTypeDef(parent, declSpecifier, declarator); |
| } |
| IASTDeclarator typeRelevant = ASTQueries.findTypeRelevantDeclarator(declarator); |
| if (typeRelevant instanceof IASTFunctionDeclarator) { |
| return createFunctionDeclaration(parent, declSpecifier, (IASTFunctionDeclarator) typeRelevant, isTemplate); |
| } |
| return createVariable(parent, declSpecifier, declarator, isTemplate); |
| } |
| |
| private void createNamespace(Parent parent, ICPPASTNamespaceDefinition declaration) |
| throws CModelException, DOMException { |
| // create element |
| final String type = Keywords.NAMESPACE; |
| final IASTName name = declaration.getName(); |
| final String nsName = ASTStringUtil.getQualifiedName(name); |
| final Namespace element = new Namespace(parent, nsName); |
| setIndex(element); |
| element.setActive(declaration.isActive()); |
| |
| // add to parent |
| parent.addChild(element); |
| // set positions |
| if (name != null && nsName.length() > 0) { |
| setIdentifierPosition(element, name); |
| } else { |
| final IASTFileLocation nsLocation = declaration.getFileLocation(); |
| if (nsLocation != null) { |
| // Note: don't want to call element.setIdPos(), because we want the SourceManipulationInfo |
| // lookup to go through the local 'fNewElements' cache. |
| getSourceManipulationInfo(element).setIdPos(nsLocation.getNodeOffset(), type.length()); |
| } |
| } |
| setBodyPosition(element, declaration); |
| |
| element.setTypeName(type); |
| |
| IASTDeclaration[] nsDeclarations = declaration.getDeclarations(true); |
| for (IASTDeclaration nsDeclaration : nsDeclarations) { |
| if (declaration.getFileLocation() != null || isLocalToFile(nsDeclaration)) { |
| createDeclaration(element, nsDeclaration); |
| } |
| } |
| } |
| |
| private StructureDeclaration createElaboratedTypeDeclaration(Parent parent, |
| IASTElaboratedTypeSpecifier elaboratedTypeSpecifier, boolean isTemplate) throws CModelException { |
| // create element |
| final String type; |
| final int kind; |
| switch (elaboratedTypeSpecifier.getKind()) { |
| case IASTElaboratedTypeSpecifier.k_struct: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_STRUCT_DECLARATION : ICElement.C_STRUCT_DECLARATION; |
| type = Keywords.STRUCT; |
| break; |
| case IASTElaboratedTypeSpecifier.k_union: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_UNION_DECLARATION : ICElement.C_UNION_DECLARATION; |
| type = Keywords.UNION; |
| break; |
| case ICPPASTElaboratedTypeSpecifier.k_class: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_CLASS_DECLARATION : ICElement.C_CLASS_DECLARATION; |
| type = Keywords.CLASS; |
| break; |
| case IASTElaboratedTypeSpecifier.k_enum: |
| // do we need a C_ENUM_DECLARATION? |
| kind = ICElement.C_CLASS_DECLARATION; |
| type = Keywords.ENUM; |
| break; |
| default: |
| kind = ICElement.C_CLASS_DECLARATION; |
| type = ""; //$NON-NLS-1$ |
| break; |
| } |
| |
| final IASTName astClassName = elaboratedTypeSpecifier.getName(); |
| final String className = ASTStringUtil.getSimpleName(astClassName); |
| |
| StructureDeclaration element; |
| if (isTemplate) { |
| element = new StructureTemplateDeclaration(parent, kind, className); |
| } else { |
| element = new StructureDeclaration(parent, className, kind); |
| } |
| setIndex(element); |
| element.setActive(elaboratedTypeSpecifier.isActive()); |
| StructureInfo info = (StructureInfo) getElementInfo(element); |
| info.setTypeName(type); |
| |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| if (className.length() > 0) { |
| setIdentifierPosition(info, astClassName); |
| } else { |
| final IASTFileLocation classLocation = getMinFileLocation(elaboratedTypeSpecifier.getNodeLocations()); |
| if (classLocation != null) { |
| info.setIdPos(classLocation.getNodeOffset(), type.length()); |
| } |
| } |
| setBodyPosition(info, elaboratedTypeSpecifier); |
| return element; |
| } |
| |
| private Enumeration createEnumeration(Parent parent, IASTEnumerationSpecifier enumSpecifier) |
| throws CModelException { |
| // create element |
| final String type = Keywords.ENUM; |
| final IASTName astEnumName = enumSpecifier.getName(); |
| final String enumName = ASTStringUtil.getSimpleName(astEnumName); |
| final Enumeration element = new Enumeration(parent, enumName); |
| setIndex(element); |
| element.setActive(enumSpecifier.isActive()); |
| |
| // add to parent |
| parent.addChild(element); |
| EnumerationInfo info = (EnumerationInfo) getElementInfo(element); |
| // set enumeration position |
| if (astEnumName != null && enumName.length() > 0) { |
| setIdentifierPosition(info, astEnumName); |
| } else { |
| final IASTFileLocation enumLocation = enumSpecifier.getFileLocation(); |
| info.setIdPos(enumLocation.getNodeOffset(), type.length()); |
| } |
| // add enumerators |
| final IASTEnumerator[] enumerators = enumSpecifier.getEnumerators(); |
| for (final IASTEnumerator enumerator : enumerators) { |
| createEnumerator(element, enumerator); |
| } |
| setBodyPosition(info, enumSpecifier); |
| info.setTypeName(type); |
| return element; |
| } |
| |
| private Enumerator createEnumerator(Parent enumarator, IASTEnumerator enumDef) throws CModelException { |
| final IASTName astEnumName = enumDef.getName(); |
| final Enumerator element = new Enumerator(enumarator, ASTStringUtil.getSimpleName(astEnumName)); |
| setIndex(element); |
| element.setActive(enumDef.isActive()); |
| |
| IASTExpression initialValue = enumDef.getValue(); |
| if (initialValue != null) { |
| element.setConstantExpression(ASTStringUtil.getExpressionString(initialValue)); |
| } |
| // add to parent |
| enumarator.addChild(element); |
| // set positions |
| setIdentifierPosition(element, astEnumName); |
| setBodyPosition(element, enumDef); |
| return element; |
| } |
| |
| private Structure createCompositeType(Parent parent, IASTCompositeTypeSpecifier compositeTypeSpecifier, |
| boolean isTemplate) throws CModelException, DOMException { |
| // create element |
| final String type; |
| final int kind; |
| final ASTAccessVisibility defaultVisibility; |
| switch (compositeTypeSpecifier.getKey()) { |
| case IASTCompositeTypeSpecifier.k_struct: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_STRUCT : ICElement.C_STRUCT; |
| type = Keywords.STRUCT; |
| defaultVisibility = ASTAccessVisibility.PUBLIC; |
| break; |
| case IASTCompositeTypeSpecifier.k_union: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_UNION : ICElement.C_UNION; |
| type = Keywords.UNION; |
| defaultVisibility = ASTAccessVisibility.PUBLIC; |
| break; |
| case ICPPASTCompositeTypeSpecifier.k_class: |
| kind = (isTemplate) ? ICElement.C_TEMPLATE_CLASS : ICElement.C_CLASS; |
| type = Keywords.CLASS; |
| defaultVisibility = ASTAccessVisibility.PRIVATE; |
| break; |
| default: |
| kind = ICElement.C_CLASS; |
| type = ""; //$NON-NLS-1$ |
| defaultVisibility = ASTAccessVisibility.PUBLIC; |
| break; |
| } |
| |
| final IASTName astClassName = compositeTypeSpecifier.getName(); |
| final String className = ASTStringUtil.getSimpleName(astClassName); |
| |
| final Structure element; |
| if (!isTemplate) { |
| Structure classElement = new Structure(parent, kind, className); |
| element = classElement; |
| } else { |
| StructureTemplate classTemplate = new StructureTemplate(parent, kind, className); |
| element = classTemplate; |
| } |
| setIndex(element); |
| element.setActive(compositeTypeSpecifier.isActive()); |
| |
| if (compositeTypeSpecifier instanceof ICPPASTCompositeTypeSpecifier) { |
| // store super classes names |
| final ICPPASTCompositeTypeSpecifier cppCompositeTypeSpecifier = (ICPPASTCompositeTypeSpecifier) compositeTypeSpecifier; |
| ICPPASTBaseSpecifier[] baseSpecifiers = cppCompositeTypeSpecifier.getBaseSpecifiers(); |
| for (final ICPPASTBaseSpecifier baseSpecifier : baseSpecifiers) { |
| final ICPPASTNameSpecifier nameSpec = baseSpecifier.getNameSpecifier(); |
| final ASTAccessVisibility visibility; |
| switch (baseSpecifier.getVisibility()) { |
| case ICPPASTBaseSpecifier.v_public: |
| visibility = ASTAccessVisibility.PUBLIC; |
| break; |
| case ICPPASTBaseSpecifier.v_protected: |
| visibility = ASTAccessVisibility.PROTECTED; |
| break; |
| case ICPPASTBaseSpecifier.v_private: |
| visibility = ASTAccessVisibility.PRIVATE; |
| break; |
| default: |
| visibility = ASTAccessVisibility.PUBLIC; |
| } |
| if (nameSpec instanceof IASTName) { |
| element.addSuperClass(ASTStringUtil.getSimpleName((IASTName) nameSpec), visibility); |
| } else { |
| element.addSuperClass(new String(nameSpec.toCharArray()), visibility); |
| } |
| } |
| } |
| |
| StructureInfo info = (StructureInfo) getElementInfo(element); |
| info.setTypeName(type); |
| |
| // add to parent |
| parent.addChild(element); |
| // set positions |
| if (!isTemplate) { |
| setBodyPosition(info, compositeTypeSpecifier); |
| } |
| if (className.length() > 0) { |
| setIdentifierPosition(info, astClassName); |
| } else { |
| final IASTFileLocation classLocation = getMinFileLocation(compositeTypeSpecifier.getNodeLocations()); |
| if (classLocation != null) { |
| info.setIdPos(classLocation.getNodeOffset(), type.length()); |
| } |
| } |
| // add members |
| pushDefaultVisibility(defaultVisibility); |
| try { |
| final IASTDeclaration[] memberDeclarations = compositeTypeSpecifier.getDeclarations(true); |
| for (IASTDeclaration member : memberDeclarations) { |
| if (compositeTypeSpecifier.getFileLocation() != null || isLocalToFile(member)) { |
| createDeclaration(element, member); |
| } |
| } |
| } finally { |
| popDefaultVisibility(); |
| } |
| return element; |
| } |
| |
| private TypeDef createTypeDef(Parent parent, IASTDeclSpecifier declSpecifier, IASTDeclarator declarator) |
| throws CModelException { |
| IASTDeclarator nestedDeclarator = declarator; |
| while (nestedDeclarator.getNestedDeclarator() != null) { |
| nestedDeclarator = nestedDeclarator.getNestedDeclarator(); |
| } |
| final IASTName astTypedefName = nestedDeclarator.getName(); |
| if (astTypedefName == null) { |
| return null; |
| } |
| // create the element |
| String name = ASTStringUtil.getSimpleName(astTypedefName); |
| |
| final TypeDef element = new TypeDef(parent, name); |
| setIndex(element); |
| element.setActive(declarator.isActive()); |
| |
| String typeName = ASTStringUtil.getSignatureString(declSpecifier, declarator); |
| element.setTypeName(typeName); |
| |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| final SourceManipulationInfo info = getSourceManipulationInfo(element); |
| if (name.length() > 0) { |
| setIdentifierPosition(info, astTypedefName); |
| } else { |
| setIdentifierPosition(info, declSpecifier); |
| } |
| if (declSpecifier instanceof IASTCompositeTypeSpecifier) { |
| setBodyPosition(info, astTypedefName); |
| } else { |
| setBodyPosition(info, declSpecifier.getParent()); |
| } |
| return element; |
| } |
| |
| private VariableDeclaration createVariable(Parent parent, IASTDeclSpecifier specifier, IASTDeclarator declarator, |
| boolean isTemplate) throws CModelException { |
| IASTDeclarator nestedDeclarator = declarator; |
| while (nestedDeclarator.getNestedDeclarator() != null) { |
| nestedDeclarator = nestedDeclarator.getNestedDeclarator(); |
| } |
| final IASTName astVariableName = nestedDeclarator.getName(); |
| if (astVariableName == null) { |
| return null; |
| } |
| final String variableName = ASTStringUtil.getQualifiedName(astVariableName); |
| |
| final VariableDeclaration element; |
| final SourceManipulationInfo info; |
| |
| if (declarator instanceof IASTFieldDeclarator || parent instanceof IStructure |
| || CModelBuilder2.getScope(astVariableName) instanceof ICPPClassScope) { |
| // field |
| Field newElement = new Field(parent, variableName); |
| setIndex(newElement); |
| final FieldInfo fieldInfo = (FieldInfo) getElementInfo(newElement); |
| if (specifier instanceof ICPPASTDeclSpecifier) { |
| final ICPPASTDeclSpecifier cppSpecifier = (ICPPASTDeclSpecifier) specifier; |
| fieldInfo.setMutable(cppSpecifier.getStorageClass() == IASTDeclSpecifier.sc_mutable); |
| } |
| fieldInfo.setTypeName(ASTStringUtil.getSignatureString(specifier, declarator)); |
| fieldInfo.setVisibility(getCurrentVisibility()); |
| fieldInfo.setConst(specifier.isConst()); |
| fieldInfo.setVolatile(specifier.isVolatile()); |
| element = newElement; |
| info = fieldInfo; |
| } else { |
| if (isTemplate) { |
| // template variable |
| VariableTemplate newElement = new VariableTemplate(parent, variableName); |
| element = newElement; |
| } else { |
| if (specifier.getStorageClass() == IASTDeclSpecifier.sc_extern) { |
| // variable declaration |
| VariableDeclaration newElement = new VariableDeclaration(parent, variableName); |
| element = newElement; |
| } else { |
| // variable |
| Variable newElement = new Variable(parent, variableName); |
| element = newElement; |
| } |
| } |
| setIndex(element); |
| VariableInfo varInfo = (VariableInfo) getElementInfo(element); |
| varInfo.setTypeName(ASTStringUtil.getSignatureString(specifier, declarator)); |
| varInfo.setConst(specifier.isConst()); |
| varInfo.setVolatile(specifier.isVolatile()); |
| info = varInfo; |
| } |
| element.setActive(declarator.isActive()); |
| // TODO [cmodel] correctly resolve isStatic |
| element.setStatic(specifier.getStorageClass() == IASTDeclSpecifier.sc_static); |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| setIdentifierPosition(info, astVariableName); |
| if (!isTemplate) { |
| if (specifier instanceof IASTCompositeTypeSpecifier) { |
| setBodyPosition(info, astVariableName); |
| } else { |
| setBodyPosition(info, specifier.getParent()); |
| } |
| } |
| return element; |
| } |
| |
| private FunctionDeclaration createFunctionDefinition(Parent parent, IASTFunctionDefinition functionDeclaration, |
| boolean isTemplate) throws CModelException, DOMException { |
| final IASTFunctionDeclarator declarator = functionDeclaration.getDeclarator(); |
| IASTDeclarator nestedDeclarator = declarator; |
| while (nestedDeclarator.getNestedDeclarator() != null) { |
| nestedDeclarator = nestedDeclarator.getNestedDeclarator(); |
| } |
| final IASTName name = nestedDeclarator.getName(); |
| if (name == null) { |
| // Something is wrong, skip this element |
| return null; |
| } |
| |
| final IASTDeclSpecifier declSpecifier = functionDeclaration.getDeclSpecifier(); |
| |
| final String simpleName = ASTStringUtil.getSimpleName(name); |
| final String[] parameterTypes = ASTStringUtil.getParameterSignatureArray(declarator); |
| final String returnType = ASTStringUtil.getReturnTypeString(declSpecifier, declarator); |
| |
| final FunctionDeclaration element; |
| final FunctionInfo info; |
| |
| if (declarator instanceof ICPPASTFunctionDeclarator) { |
| final ICPPASTFunctionDeclarator cppFunctionDeclarator = (ICPPASTFunctionDeclarator) declarator; |
| final IASTName simpleAstName; |
| if (name instanceof ICPPASTQualifiedName) { |
| final ICPPASTQualifiedName quName = (ICPPASTQualifiedName) name; |
| simpleAstName = quName.getLastName(); |
| } else { |
| simpleAstName = name; |
| } |
| IScope scope = null; |
| // try to avoid expensive resolution of scope and binding |
| boolean isMethod = parent instanceof IStructure; |
| if (!isMethod && name instanceof ICPPASTQualifiedName) { |
| if (isTemplate) { |
| final ICPPASTNameSpecifier[] segments = ((ICPPASTQualifiedName) name).getAllSegments(); |
| for (ICPPASTNameSpecifier segment : segments) { |
| if (segment instanceof ICPPASTTemplateId) { |
| isMethod = true; |
| break; |
| } |
| } |
| } |
| if (!isMethod) { |
| scope = CPPVisitor.getContainingScope(simpleAstName); |
| isMethod = scope instanceof ICPPClassScope || simpleAstName.resolveBinding() instanceof ICPPMethod; |
| } |
| } |
| if (isMethod) { |
| // method |
| final MethodDeclaration methodElement; |
| final String methodName; |
| if (parent instanceof IStructure) { |
| methodName = ASTStringUtil.getSimpleName(name); |
| } else { |
| methodName = ASTStringUtil.getQualifiedName(name); |
| } |
| if (isTemplate) { |
| methodElement = new MethodTemplate(parent, methodName); |
| } else { |
| methodElement = new Method(parent, methodName); |
| } |
| element = methodElement; |
| // establish identity attributes before getElementInfo() |
| methodElement.setParameterTypes(parameterTypes); |
| methodElement.setReturnType(returnType); |
| methodElement.setConst(cppFunctionDeclarator.isConst()); |
| setIndex(element); |
| |
| final MethodInfo methodInfo = (MethodInfo) getElementInfo(methodElement); |
| info = methodInfo; |
| ICPPMethod methodBinding = null; |
| if (scope != null) { |
| final IBinding binding = simpleAstName.resolveBinding(); |
| if (binding instanceof ICPPMethod) { |
| methodBinding = (ICPPMethod) binding; |
| } |
| } |
| if (methodBinding != null) { |
| methodInfo.setVirtual(methodBinding.isVirtual()); |
| methodInfo.setInline(methodBinding.isInline()); |
| methodInfo.setFriend(((ICPPASTDeclSpecifier) declSpecifier).isFriend()); |
| methodInfo.setVolatile(cppFunctionDeclarator.isVolatile()); |
| methodInfo.setVisibility(adaptVisibilityConstant(methodBinding.getVisibility())); |
| methodInfo.setPureVirtual(false); |
| methodElement.setConstructor(methodBinding instanceof ICPPConstructor); |
| methodElement.setDestructor(methodBinding.isDestructor()); |
| } else { |
| if (declSpecifier instanceof ICPPASTDeclSpecifier) { |
| final ICPPASTDeclSpecifier cppDeclSpecifier = (ICPPASTDeclSpecifier) declSpecifier; |
| methodInfo.setVirtual(cppDeclSpecifier.isVirtual()); |
| methodInfo.setInline(cppDeclSpecifier.isInline()); |
| methodInfo.setFriend(cppDeclSpecifier.isFriend()); |
| } |
| methodInfo.setVolatile(cppFunctionDeclarator.isVolatile()); |
| methodInfo.setVisibility(getCurrentVisibility()); |
| methodInfo.setPureVirtual(false); |
| final boolean isConstructor; |
| if (scope != null) { |
| isConstructor = CPPVisitor.isConstructor(scope, declarator); |
| } else if (parent instanceof IStructure) { |
| isConstructor = parent.getElementName().equals(simpleName); |
| } else if (name instanceof ICPPASTQualifiedName) { |
| final ICPPASTQualifiedName quName = (ICPPASTQualifiedName) name; |
| final ICPPASTNameSpecifier[] qualifier = quName.getQualifier(); |
| if (qualifier.length == 0) |
| isConstructor = false; |
| else { |
| ICPPASTNameSpecifier nameSpec = qualifier[qualifier.length - 1]; |
| isConstructor = nameSpec instanceof IASTName |
| && simpleName.equals(ASTStringUtil.getSimpleName((IASTName) nameSpec)); |
| } |
| } else { |
| isConstructor = false; |
| } |
| methodElement.setConstructor(isConstructor); |
| methodElement.setDestructor(simpleName.charAt(0) == '~'); |
| } |
| } else { |
| String functionName = ASTStringUtil.getQualifiedName(name); |
| // strip namespace qualifier if parent is same namespace |
| if (name instanceof ICPPASTQualifiedName && parent instanceof INamespace) { |
| final ICPPASTQualifiedName quName = (ICPPASTQualifiedName) name; |
| final ICPPASTNameSpecifier[] qualifier = quName.getQualifier(); |
| if (qualifier.length >= 1) { |
| ICPPASTNameSpecifier nameSpec = qualifier[qualifier.length - 1]; |
| if (nameSpec instanceof IASTName |
| && parent.getElementName().equals(ASTStringUtil.getSimpleName((IASTName) nameSpec))) { |
| functionName = simpleName; |
| } |
| } |
| } |
| if (isTemplate) { |
| // template function |
| element = new FunctionTemplate(parent, functionName); |
| } else { |
| // function |
| element = new Function(parent, functionName); |
| } |
| element.setParameterTypes(parameterTypes); |
| element.setReturnType(returnType); |
| setIndex(element); |
| |
| info = (FunctionInfo) getElementInfo(element); |
| info.setConst(cppFunctionDeclarator.isConst()); |
| } |
| |
| } else { |
| final String functionName = ASTStringUtil.getQualifiedName(name); |
| element = new Function(parent, functionName); |
| element.setParameterTypes(parameterTypes); |
| element.setReturnType(returnType); |
| setIndex(element); |
| |
| info = (FunctionInfo) getElementInfo(element); |
| } |
| element.setActive(functionDeclaration.isActive()); |
| |
| // TODO [cmodel] correctly resolve isStatic |
| info.setStatic(declSpecifier.getStorageClass() == IASTDeclSpecifier.sc_static); |
| |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| setIdentifierPosition(info, name); |
| if (!isTemplate) { |
| setBodyPosition(info, functionDeclaration); |
| } |
| return element; |
| } |
| |
| private FunctionDeclaration createFunctionDeclaration(Parent parent, IASTDeclSpecifier declSpecifier, |
| IASTFunctionDeclarator declarator, boolean isTemplate) throws CModelException { |
| IASTDeclarator nestedDeclarator = declarator; |
| while (nestedDeclarator.getNestedDeclarator() != null) { |
| nestedDeclarator = nestedDeclarator.getNestedDeclarator(); |
| } |
| final IASTName name = nestedDeclarator.getName(); |
| if (name == null) { |
| // Something is wrong, skip this element |
| return null; |
| } |
| |
| final String functionName = ASTStringUtil.getSimpleName(name); |
| final String[] parameterTypes = ASTStringUtil.getParameterSignatureArray(declarator); |
| final String returnType = ASTStringUtil.getReturnTypeString(declSpecifier, declarator); |
| |
| final FunctionDeclaration element; |
| final FunctionInfo info; |
| |
| if (declarator instanceof ICPPASTFunctionDeclarator) { |
| final ICPPASTFunctionDeclarator cppFunctionDeclarator = (ICPPASTFunctionDeclarator) declarator; |
| if (parent instanceof IStructure) { |
| // method |
| final MethodDeclaration methodElement; |
| if (isTemplate) { |
| methodElement = new MethodTemplateDeclaration(parent, functionName); |
| } else { |
| methodElement = new MethodDeclaration(parent, functionName); |
| } |
| element = methodElement; |
| // establish identity attributes before getElementInfo() |
| methodElement.setParameterTypes(parameterTypes); |
| methodElement.setReturnType(returnType); |
| methodElement.setConst(cppFunctionDeclarator.isConst()); |
| setIndex(element); |
| final MethodInfo methodInfo = (MethodInfo) getElementInfo(methodElement); |
| info = methodInfo; |
| if (declSpecifier instanceof ICPPASTDeclSpecifier) { |
| final ICPPASTDeclSpecifier cppDeclSpecifier = (ICPPASTDeclSpecifier) declSpecifier; |
| methodInfo.setVirtual(cppDeclSpecifier.isVirtual()); |
| methodInfo.setInline(cppDeclSpecifier.isInline()); |
| methodInfo.setFriend(cppDeclSpecifier.isFriend()); |
| } |
| methodInfo.setVolatile(cppFunctionDeclarator.isVolatile()); |
| methodInfo.setVisibility(getCurrentVisibility()); |
| methodInfo.setPureVirtual(cppFunctionDeclarator.isPureVirtual()); |
| methodElement.setConstructor(functionName.equals(parent.getElementName())); |
| methodElement.setDestructor(functionName.charAt(0) == '~'); |
| } else { |
| if (isTemplate) { |
| element = new FunctionTemplateDeclaration(parent, functionName); |
| } else { |
| element = new FunctionDeclaration(parent, functionName); |
| } |
| element.setParameterTypes(parameterTypes); |
| element.setReturnType(returnType); |
| setIndex(element); |
| |
| info = (FunctionInfo) getElementInfo(element); |
| info.setConst(cppFunctionDeclarator.isConst()); |
| } |
| } else if (declarator instanceof IASTStandardFunctionDeclarator) { |
| if (isTemplate) { |
| element = new FunctionTemplateDeclaration(parent, functionName); |
| } else { |
| element = new FunctionDeclaration(parent, functionName); |
| } |
| element.setParameterTypes(parameterTypes); |
| element.setReturnType(returnType); |
| setIndex(element); |
| |
| info = (FunctionInfo) getElementInfo(element); |
| } else { |
| assert false; |
| return null; |
| } |
| element.setActive(declarator.isActive()); |
| |
| // TODO [cmodel] correctly resolve isStatic |
| info.setStatic(declSpecifier.getStorageClass() == IASTDeclSpecifier.sc_static); |
| |
| // add to parent |
| parent.addChild(element); |
| |
| // hook up the offsets |
| setIdentifierPosition(info, name); |
| if (!isTemplate) { |
| setBodyPosition(info, declarator.getParent()); |
| } |
| return element; |
| } |
| |
| private Using createUsingDirective(Parent parent, ICPPASTUsingDirective usingDirDeclaration) |
| throws CModelException { |
| // create the element |
| IASTName name = usingDirDeclaration.getQualifiedName(); |
| Using element = new Using(parent, ASTStringUtil.getQualifiedName(name), true); |
| setIndex(element); |
| element.setActive(usingDirDeclaration.isActive()); |
| |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| setIdentifierPosition(element, name); |
| setBodyPosition(element, usingDirDeclaration); |
| return element; |
| } |
| |
| private Using createUsingDeclaration(Parent parent, ICPPASTUsingDeclaration usingDeclaration) |
| throws CModelException { |
| // create the element |
| IASTName name = usingDeclaration.getName(); |
| Using element = new Using(parent, ASTStringUtil.getSimpleName(name), false); |
| setIndex(element); |
| element.setActive(usingDeclaration.isActive()); |
| // add to parent |
| parent.addChild(element); |
| |
| // set positions |
| setIdentifierPosition(element, name); |
| setBodyPosition(element, usingDeclaration); |
| return element; |
| } |
| |
| private CElementInfo getElementInfo(CElement cElement) { |
| CElementInfo info = fNewElements.get(cElement); |
| if (info == null) { |
| info = cElement.createElementInfo(); |
| fNewElements.put(cElement, info); |
| } |
| return info; |
| } |
| |
| private SourceManipulationInfo getSourceManipulationInfo(SourceManipulation cElement) { |
| return (SourceManipulationInfo) getElementInfo(cElement); |
| } |
| |
| /** |
| * Utility method to set the body position of an element from an AST node. |
| * |
| * @param element |
| * @param astNode |
| * @throws CModelException |
| */ |
| private void setBodyPosition(SourceManipulation element, IASTNode astNode) throws CModelException { |
| setBodyPosition(getSourceManipulationInfo(element), astNode); |
| } |
| |
| /** |
| * Utility method to set the body position of an element from an AST node. |
| * |
| * @param info |
| * @param astNode |
| */ |
| private void setBodyPosition(SourceManipulationInfo info, IASTNode astNode) { |
| final IASTFileLocation location = astNode.getFileLocation(); |
| if (location != null) { |
| info.setPos(location.getNodeOffset(), location.getNodeLength()); |
| info.setLines(location.getStartingLineNumber(), location.getEndingLineNumber()); |
| } else { |
| final IASTNodeLocation[] locations = astNode.getNodeLocations(); |
| final IASTFileLocation minLocation = getMinFileLocation(locations); |
| if (minLocation != null) { |
| final IASTFileLocation maxLocation = getMaxFileLocation(locations); |
| if (maxLocation != null) { |
| final int startOffset = minLocation.getNodeOffset(); |
| final int endOffset = maxLocation.getNodeOffset() + maxLocation.getNodeLength(); |
| info.setPos(startOffset, endOffset - startOffset); |
| final int startLine = minLocation.getStartingLineNumber(); |
| final int endLine = maxLocation.getEndingLineNumber(); |
| info.setLines(startLine, endLine); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Utility method to set the identifier position of an element from an AST name. |
| * |
| * @param element |
| * @param astName |
| */ |
| private void setIdentifierPosition(SourceManipulation element, IASTName astName) { |
| setIdentifierPosition(getSourceManipulationInfo(element), astName); |
| } |
| |
| /** |
| * Utility method to set the identifier position of an element from an AST name. |
| * |
| * @param info |
| * @param astName |
| */ |
| private void setIdentifierPosition(SourceManipulationInfo info, IASTNode astName) { |
| final IASTFileLocation location = astName.getFileLocation(); |
| if (location != null) { |
| info.setIdPos(location.getNodeOffset(), location.getNodeLength()); |
| } else { |
| final IASTNodeLocation[] locations = astName.getNodeLocations(); |
| final IASTFileLocation minLocation = getMinFileLocation(locations); |
| if (minLocation != null) { |
| final IASTFileLocation maxLocation = getMaxFileLocation(locations); |
| if (maxLocation != null) { |
| final int startOffset = minLocation.getNodeOffset(); |
| final int endOffset = maxLocation.getNodeOffset() + maxLocation.getNodeLength(); |
| info.setIdPos(startOffset, endOffset - startOffset); |
| } |
| } |
| } |
| } |
| |
| private static IASTFileLocation getMaxFileLocation(IASTNodeLocation[] locations) { |
| if (locations == null || locations.length == 0) { |
| return null; |
| } |
| final IASTNodeLocation nodeLocation = locations[locations.length - 1]; |
| return nodeLocation.asFileLocation(); |
| } |
| |
| private static IASTFileLocation getMinFileLocation(IASTNodeLocation[] locations) { |
| if (locations == null || locations.length == 0) { |
| return null; |
| } |
| final IASTNodeLocation nodeLocation = locations[0]; |
| return nodeLocation.asFileLocation(); |
| } |
| |
| /** |
| * Handle the special "declaration" visibility label |
| * @param visibilityLabel |
| */ |
| private void handleVisibilityLabel(ICPPASTVisibilityLabel visibilityLabel) { |
| setCurrentVisibility(adaptVisibilityConstant(visibilityLabel.getVisibility())); |
| } |
| |
| /** |
| * Convert the given <code>ICPPASTVisiblityLabel</code> visibility constant |
| * into an <code>ASTAccessVisibility</code>. |
| * |
| * @param visibility |
| * @return the corresponding <code>ASTAccessVisibility</code> |
| */ |
| private ASTAccessVisibility adaptVisibilityConstant(int visibility) { |
| switch (visibility) { |
| case ICPPASTVisibilityLabel.v_public: |
| return ASTAccessVisibility.PUBLIC; |
| case ICPPASTVisibilityLabel.v_protected: |
| return ASTAccessVisibility.PROTECTED; |
| case ICPPASTVisibilityLabel.v_private: |
| return ASTAccessVisibility.PRIVATE; |
| } |
| assert false : "Unknown visibility"; //$NON-NLS-1$ |
| return ASTAccessVisibility.PUBLIC; |
| } |
| |
| private void setCurrentVisibility(ASTAccessVisibility visibility) { |
| fCurrentVisibility = visibility; |
| } |
| |
| private ASTAccessVisibility getCurrentVisibility() { |
| if (fCurrentVisibility == null) { |
| return ASTAccessVisibility.PUBLIC; |
| } |
| return fCurrentVisibility; |
| } |
| |
| /** |
| * Pop the default visibility from the outer scope. |
| */ |
| private void popDefaultVisibility() { |
| if (!fVisibilityStack.isEmpty()) { |
| setCurrentVisibility(fVisibilityStack.pop()); |
| } |
| } |
| |
| /** |
| * Push given visibility as default class/struct/union visibility. |
| * |
| * @param visibility |
| */ |
| private void pushDefaultVisibility(ASTAccessVisibility visibility) { |
| fVisibilityStack.push(getCurrentVisibility()); |
| setCurrentVisibility(visibility); |
| } |
| |
| /** |
| * Determine the scope for given name. |
| * |
| * @param astName |
| * @return the scope or <code>null</code> |
| */ |
| private static IScope getScope(IASTName astName) { |
| IBinding binding = astName.resolveBinding(); |
| if (binding != null) { |
| try { |
| return binding.getScope(); |
| } catch (DOMException e) { |
| return null; |
| } |
| } |
| return null; |
| } |
| } |