/*
* 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.module.extension;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
import consulo.annotations.RequiredReadAction;
import consulo.csharp.compiler.CSharpPlatform;
import consulo.csharp.compiler.MSBaseDotNetCompilerOptionsBuilder;
import consulo.csharp.lang.evaluator.ConstantExpressionEvaluator;
import consulo.csharp.lang.psi.CSharpAttribute;
import consulo.csharp.lang.psi.CSharpAttributeList;
import consulo.csharp.lang.psi.CSharpMethodDeclaration;
import consulo.csharp.lang.psi.impl.stub.index.AttributeListIndex;
import consulo.csharp.lang.psi.impl.stub.index.MethodIndex;
import consulo.dotnet.DotNetRunUtil;
import consulo.dotnet.DotNetTypes;
import consulo.dotnet.compiler.DotNetCompilerOptionsBuilder;
import consulo.dotnet.module.extension.DotNetModuleLangExtension;
import consulo.dotnet.psi.DotNetAttributeTargetType;
import consulo.dotnet.psi.DotNetExpression;
import consulo.dotnet.psi.DotNetLikeMethodDeclaration;
import consulo.dotnet.psi.DotNetMethodDeclaration;
import consulo.dotnet.psi.DotNetTypeDeclaration;
import consulo.module.extension.MutableModuleInheritableNamedPointer;
import consulo.roots.ModuleRootLayer;
/**
* @author VISTALL
* @since 15.12.13.
*/
public abstract class BaseCSharpModuleExtension<T extends BaseCSharpModuleExtension<T>> extends BaseCSharpSimpleModuleExtension<T> implements
DotNetModuleLangExtension<T>, CSharpModuleExtension<T>
{
protected boolean myOptimizeCode;
protected CSharpPlatform myPlatform = CSharpPlatform.ANY_CPU;
protected String myCompilerTarget;
protected CSharpCustomCompilerSdkPointer myCustomCompilerSdkPointer;
public BaseCSharpModuleExtension(@NotNull String id, @NotNull ModuleRootLayer layer)
{
super(id, layer);
myCustomCompilerSdkPointer = new CSharpCustomCompilerSdkPointer(layer, id);
}
@Override
public void setCompilerExecutable(@NotNull DotNetCompilerOptionsBuilder builder, @NotNull VirtualFile executable)
{
((MSBaseDotNetCompilerOptionsBuilder) builder).setExecutable(executable.getPath());
}
@NotNull
@Override
public MutableModuleInheritableNamedPointer<Sdk> getCustomCompilerSdkPointer()
{
return myCustomCompilerSdkPointer;
}
@NotNull
@Override
@RequiredReadAction
public PsiElement[] getEntryPointElements()
{
final List<DotNetTypeDeclaration> typeDeclarations = new ArrayList<DotNetTypeDeclaration>();
Collection<DotNetLikeMethodDeclaration> methods = MethodIndex.getInstance().get("Main", getProject(), getModule().getModuleScope());
for(DotNetLikeMethodDeclaration method : methods)
{
if(method instanceof CSharpMethodDeclaration && DotNetRunUtil.isEntryPoint((DotNetMethodDeclaration) method))
{
Module moduleForPsiElement = ModuleUtilCore.findModuleForPsiElement(method);
// scope is broken?
if(!getModule().equals(moduleForPsiElement))
{
continue;
}
typeDeclarations.add((DotNetTypeDeclaration) method.getParent());
}
}
return ContainerUtil.toArray(typeDeclarations, DotNetTypeDeclaration.ARRAY_FACTORY);
}
@Nullable
@Override
@RequiredReadAction
public String getAssemblyTitle()
{
GlobalSearchScope moduleScope = getModule().getModuleScope();
Collection<CSharpAttributeList> attributeLists = AttributeListIndex.getInstance().get(DotNetAttributeTargetType.ASSEMBLY, getProject(), moduleScope);
loop:for(CSharpAttributeList attributeList : attributeLists)
{
for(CSharpAttribute attribute : attributeList.getAttributes())
{
DotNetTypeDeclaration typeDeclaration = attribute.resolveToType();
if(typeDeclaration == null)
{
continue;
}
if(DotNetTypes.System.Reflection.AssemblyTitleAttribute.equals(typeDeclaration.getVmQName()))
{
Module attributeModule = ModuleUtilCore.findModuleForPsiElement(attribute);
if(attributeModule == null || !attributeModule.equals(getModule()))
{
continue;
}
DotNetExpression[] parameterExpressions = attribute.getParameterExpressions();
if(parameterExpressions.length == 0)
{
break loop;
}
String valueAs = new ConstantExpressionEvaluator(parameterExpressions[0]).getValueAs(String.class);
if(valueAs != null)
{
return valueAs;
}
}
}
}
return null;
}
@NotNull
@Override
public CSharpPlatform getPlatform()
{
return myPlatform;
}
@Override
public boolean isOptimizeCode()
{
return myOptimizeCode;
}
public void setPlatform(@NotNull CSharpPlatform platform)
{
myPlatform = platform;
}
public void setOptimizeCode(boolean optimizeCode)
{
myOptimizeCode = optimizeCode;
}
@Override
public boolean isModifiedImpl(@NotNull T mutableModuleExtension)
{
return super.isModifiedImpl(mutableModuleExtension) ||
myOptimizeCode != mutableModuleExtension.myOptimizeCode ||
myPlatform != mutableModuleExtension.myPlatform ||
!myCustomCompilerSdkPointer.equals(mutableModuleExtension.myCustomCompilerSdkPointer) ||
!Comparing.equal(myCompilerTarget, mutableModuleExtension.myCompilerTarget);
}
@RequiredReadAction
@Override
protected void loadStateImpl(@NotNull Element element)
{
super.loadStateImpl(element);
myOptimizeCode = Boolean.valueOf(element.getAttributeValue("optimize-code", "false"));
myPlatform = CSharpPlatform.valueOf(element.getAttributeValue("platform", CSharpPlatform.ANY_CPU.name()));
myCompilerTarget = element.getAttributeValue("compiler-target");
myCustomCompilerSdkPointer.fromXml(element);
}
@Override
protected void getStateImpl(@NotNull Element element)
{
super.getStateImpl(element);
element.setAttribute("optimize-code", Boolean.toString(myOptimizeCode));
element.setAttribute("platform", myPlatform.name());
if(myCompilerTarget != null)
{
element.setAttribute("compiler-target", myCompilerTarget);
}
myCustomCompilerSdkPointer.toXml(element);
}
@Override
public void commit(@NotNull T mutableModuleExtension)
{
super.commit(mutableModuleExtension);
myOptimizeCode = mutableModuleExtension.myOptimizeCode;
myPlatform = mutableModuleExtension.myPlatform;
myCompilerTarget = mutableModuleExtension.myCompilerTarget;
myCustomCompilerSdkPointer.set(mutableModuleExtension.myCustomCompilerSdkPointer);
}
@Nullable
@Override
public String getCompilerTarget()
{
return myCompilerTarget;
}
public void setCompilerTarget(@Nullable String target)
{
myCompilerTarget = target;
}
}