/*******************************************************************************
* Copyright (c) 2009, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.HashSet;
import java.util.LinkedList;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
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.IASTDeclarationStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTElaboratedTypeSpecifier;
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.internal.core.dom.parser.ASTAmbiguousNode;
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
/**
* Visitor to resolve ast ambiguities in the right order
*/
final class CPPASTAmbiguityResolver extends ASTVisitor {
private int fSkipInitializers= 0;
private int fDeferFunctions= 1;
private HashSet<IASTDeclaration> fRepopulate= new HashSet<IASTDeclaration>();
private LinkedList<IASTNode> fDeferredNodes= new LinkedList<IASTNode>();
public CPPASTAmbiguityResolver() {
super(false);
includeInactiveNodes= true;
shouldVisitAmbiguousNodes= true;
shouldVisitDeclarations= true;
shouldVisitDeclSpecifiers= true;
shouldVisitInitializers= true;
shouldVisitTranslationUnit= true;
}
@Override
public int visit(ASTAmbiguousNode astAmbiguousNode) {
IASTNode node= astAmbiguousNode.resolveAmbiguity(this);
if (node instanceof IASTDeclarator) {
while (node != null) {
if (node instanceof IASTDeclaration) {
fRepopulate.add((IASTDeclaration) node);
break;
}
if (node instanceof IASTParameterDeclaration) {
// If the parameter declaration belongs to a function declaration or
// function definition we need to update the scope.
IASTNode parent= node.getParent();
if (parent instanceof IASTDeclarator) {
IASTDeclarator dtor= (IASTDeclarator) parent;
if (dtor == ASTQueries.findTypeRelevantDeclarator(dtor) &&
ASTQueries.findOutermostDeclarator(dtor).getParent() instanceof IASTDeclaration) {
repopulateScope((IASTParameterDeclaration) node);
}
}
break;
}
if (node instanceof IASTExpression) {
break;
}
node= node.getParent();
}
} else if (node instanceof IASTDeclarationStatement) {
repopulateScope(((IASTDeclarationStatement) node).getDeclaration());
} else if (node instanceof IASTDeclaration) {
repopulateScope((IASTDeclaration) node);
}
return PROCESS_SKIP;
}
@Override
public int visit(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
fDeferFunctions++;
}
return PROCESS_CONTINUE;
}
@Override
public int leave(IASTDeclSpecifier declSpec) {
if (declSpec instanceof ICPPASTCompositeTypeSpecifier) {
fDeferFunctions--;
// Resolve class type definitions, such that the scope is available
// during ambiguity resolution.
((ICPPASTCompositeTypeSpecifier) declSpec).getName().resolveBinding();
// Trigger computation of implicit members.
if (declSpec instanceof CPPASTCompositeTypeSpecifier)
((CPPASTCompositeTypeSpecifier) declSpec).setAmbiguitiesResolved();
}
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTDeclaration decl) {
if (fDeferFunctions > 0 && decl instanceof IASTFunctionDefinition) {
final IASTFunctionDefinition fdef= (IASTFunctionDefinition) decl;
// visit the declarator first, it may contain ambiguous template arguments needed
// for associating the template declarations.
fSkipInitializers++;
ASTQueries.findOutermostDeclarator(fdef.getDeclarator()).accept(this);
fSkipInitializers--;
fdef.getDeclSpecifier().accept(this);
// defer visiting the body of the function until the class body has been visited.
fDeferredNodes.add(decl);
return PROCESS_SKIP;
}
return PROCESS_CONTINUE;
}
@Override
public int leave(IASTDeclaration declaration) {
if (fRepopulate.remove(declaration)) {
repopulateScope(declaration);
}
// We need to create class bindings for all definitions and for the specializations.
// Otherwise, name resolution cannot access members or correct specialization.
if (declaration instanceof IASTSimpleDeclaration) {
IASTSimpleDeclaration sdecl= (IASTSimpleDeclaration) declaration;
IASTName name= null;
IASTDeclSpecifier declspec = sdecl.getDeclSpecifier();
if (declspec instanceof IASTCompositeTypeSpecifier) {
// Definition of a class[template[specialization]]
name= ((IASTCompositeTypeSpecifier) declspec).getName().getLastName();
} else if (declspec instanceof ICPPASTElaboratedTypeSpecifier
&& sdecl.getDeclarators().length == 0) {
ASTNodeProperty prop = declaration.getPropertyInParent();
if (prop == ICPPASTTemplateDeclaration.OWNED_DECLARATION
|| prop == ICPPASTTemplateSpecialization.OWNED_DECLARATION) {
ICPPASTElaboratedTypeSpecifier elab= (ICPPASTElaboratedTypeSpecifier) declspec;
if (!elab.isFriend()) {
// Declaration of a class template specialization.
name= elab.getName().getLastName();
}
}
}
if (name instanceof ICPPASTTemplateId) {
name.resolveBinding();
}
}
return PROCESS_CONTINUE;
}
@Override
public int visit(IASTInitializer initializer) {
if (fSkipInitializers > 0)
return PROCESS_SKIP;
return PROCESS_CONTINUE;
}
@Override
public int leave(IASTTranslationUnit tu) {
while (!fDeferredNodes.isEmpty()) {
fDeferFunctions= 0;
fDeferredNodes.removeFirst().accept(this);
}
return PROCESS_CONTINUE;
}
private void repopulateScope(IASTDeclaration declaration) {
IScope scope= CPPVisitor.getContainingNonTemplateScope(declaration);
if (scope instanceof ICPPASTInternalScope) {
CPPSemantics.populateCache((ICPPASTInternalScope) scope, declaration);
}
}
private void repopulateScope(IASTParameterDeclaration declaration) {
IScope scope= CPPVisitor.getContainingNonTemplateScope(declaration);
if (scope instanceof ICPPASTInternalScope) {
CPPSemantics.populateCache((ICPPASTInternalScope) scope, declaration);
}
}
}