/* * Copyright 2013-2017 consulo.io * * 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. */ package consulo.csharp.lang.psi.impl.msil.typeParsing; import java.util.ArrayList; import java.util.List; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.IntArrayList; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpGenericWrapperTypeRef; import consulo.csharp.lang.psi.impl.source.resolve.type.CSharpTypeRefFromText; import consulo.dotnet.DotNetTypes; import consulo.dotnet.resolve.DotNetTypeRef; /** * @author VISTALL * @since 11.07.14 */ public class SomeTypeParser { private static final Logger LOGGER = Logger.getInstance(SomeTypeParser.class); @NotNull public static DotNetTypeRef toDotNetTypeRef(String text, String nameFromBytecode, PsiElement scope) { SomeType someType = parseType(text, nameFromBytecode); if(someType == null) { return DotNetTypeRef.ERROR_TYPE; } return convert(someType, scope); } public static DotNetTypeRef convert(@NotNull SomeType type, @NotNull final PsiElement scope) { final Ref<DotNetTypeRef> typeRefRef = new Ref<DotNetTypeRef>(); type.accept(new SomeTypeVisitor() { @Override public void visitUserType(UserType userType) { typeRefRef.set(new CSharpTypeRefFromText(userType.getText(), scope)); } @Override public void visitGenericWrapperType(GenericWrapperType genericWrapperType) { List<SomeType> arguments = genericWrapperType.getArguments(); List<DotNetTypeRef> typeRefs = new ArrayList<DotNetTypeRef>(arguments.size()); for(SomeType argument : arguments) { typeRefs.add(convert(argument, scope)); } typeRefRef.set(new CSharpGenericWrapperTypeRef(convert(genericWrapperType.getTarget(), scope), typeRefs.toArray(new DotNetTypeRef[typeRefs.size()]))); } }); return typeRefRef.get(); } @Nullable public static SomeType parseType(String text, final String nameFromBytecode) { if(StringUtil.isEmpty(text)) { return null; } try { int i = text.indexOf("<"); if(i != -1) { String innerType = text.substring(0, i); String argumentsList = text.substring(i + 1, text.lastIndexOf(">")); List<String> types = splitButIgnoreInsideLtGt(argumentsList); List<SomeType> map = ContainerUtil.map(types, new Function<String, SomeType>() { @Override public SomeType fun(String s) { return parseType(s, nameFromBytecode); } }); return new GenericWrapperType(new UserType(innerType), map); } else { return new UserType(text); } } catch(Exception e) { SomeTypeParser.LOGGER.error("Type " + nameFromBytecode + " cant parsed"); return new UserType(DotNetTypes.System.Object); } } private static List<String> splitButIgnoreInsideLtGt(String text) { IntArrayList list = new IntArrayList(); int dep = 0; char[] chars = text.toCharArray(); for(int i = 0; i < chars.length; i++) { switch(chars[i]) { case '<': dep++; break; case '>': dep--; break; case ',': if(dep == 0) { list.add(i); } break; } } list.add(text.length()); List<String> split = new ArrayList<String>(list.size()); int last = 0; for(int i : list.toArray()) { String substring = text.substring(last, i); split.add(substring); last = i + 1; } return split; } }