Bug 568625 - "Invalid arguments" using __underlying_type outside template

ICPPUnaryTypeTransformation was meant to be used only when the
transformation is applied on a dependent type. But it was actually
always used when creating types for decl specifiers, regardless if a
dependent type was involved or not. The untransformed type was causing
issues because code dealing with ITypes doesn't apply the transformation
everywhere. It seems better to apply the transformation early when
possible and let the rest of the logic intact.

Change-Id: I1b6d77a857e901f71f00e935e75d24cea87c3118
Signed-off-by: Marc-Andre Laperle <malaperle@gmail.com>
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
index fe3fce6..bcf3f34 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
@@ -11382,6 +11382,19 @@
 		parseAndCheckBindings(getAboveComment(), CPP, true /* use GNU extensions */);
 	}
 
+	//	enum class TestEnum : char {
+	//	};
+	//
+	//	void bar(__underlying_type(TestEnum) as) {
+	//	}
+	//
+	//	void foo() {
+	//	  bar('a'); // Invalid arguments 'Candidates are: void bar(@120932903)'
+	//	}
+	public void testUnderlyingType_568625() throws Exception {
+		parseAndCheckBindings(getAboveComment(), CPP, true /* use GNU extensions */);
+	}
+
 	//	void ptrFunc(void*);
 	//	void intFunc(int);
 	//	void foo(int* pi, unsigned i) {
@@ -13636,6 +13649,7 @@
 	//		Test<__is_same(Enum, Enum)>::true_val;
 	//		Test<__is_same(Enum, int)>::false_val;
 	//		Test<__is_same(EnumChar, char)>::false_val;
+	//		Test<__is_same(__underlying_type(EnumChar), char)>::true_val;
 	//
 	//		Test<TemplateArgs<int, bool>::Value>::false_val;
 	//		Test<TemplateArgs<int, int>::Value>::true_val;
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
index 96e1d2c..a4a8339 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java
@@ -1717,12 +1717,7 @@
 			if (type instanceof ICPPUnaryTypeTransformation) {
 				ICPPUnaryTypeTransformation typeTransformation = (ICPPUnaryTypeTransformation) type;
 				IType operand = instantiateType(typeTransformation.getOperand(), context);
-				switch (typeTransformation.getOperator()) {
-				case underlying_type:
-					return TypeTraits.underlyingType(operand);
-				default:
-					return null; // shouldn't happen
-				}
+				return SemanticUtil.applyTypeTransformation(typeTransformation.getOperator(), operand);
 			}
 
 			if (type instanceof CPPClosureType) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index 11cc476..80858af 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -236,7 +236,6 @@
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateParameterMap;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateTypeArgument;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTypedef;
-import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnaryTypeTransformation;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPUnknownTypeScope;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariable;
 import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPVariableTemplate;
@@ -2793,7 +2792,12 @@
 			name = ((IASTEnumerationSpecifier) declSpec).getName();
 		} else if (declSpec instanceof ICPPASTTypeTransformationSpecifier) {
 			ICPPASTTypeTransformationSpecifier spec = (ICPPASTTypeTransformationSpecifier) declSpec;
-			return new CPPUnaryTypeTransformation(spec.getOperator(), createType(spec.getOperand()));
+			IType type = SemanticUtil.applyTypeTransformation(spec.getOperator(), createType(spec.getOperand()));
+			if (type != null)
+				return type;
+
+			return ProblemType.UNRESOLVED_NAME;
+
 		} else if (declSpec instanceof ICPPASTSimpleDeclSpecifier) {
 			ICPPASTSimpleDeclSpecifier spec = (ICPPASTSimpleDeclSpecifier) declSpec;
 			// Check for decltype(expr)
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
index f84d285..ebf6c6d 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/SemanticUtil.java
@@ -68,6 +68,7 @@
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
 import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPUnaryTypeTransformation;
 import org.eclipse.cdt.core.index.IIndexBinding;
 import org.eclipse.cdt.core.parser.Keywords;
 import org.eclipse.cdt.core.parser.util.ArrayUtil;
@@ -945,4 +946,13 @@
 		}
 		return result;
 	}
+
+	public static IType applyTypeTransformation(ICPPUnaryTypeTransformation.Operator operator, IType type) {
+		switch (operator) {
+		case underlying_type:
+			return TypeTraits.underlyingType(type);
+		default:
+			return null; // shouldn't happen
+		}
+	}
 }