Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PackageLock Include="Fantomas.FCS" Version="7.0.3" />
<PackageLock Include="FSharp.Core" Version="9.0.201" />
<PackageLock Include="JetBrains.Lifetimes" Version="2025.3.1" />
<PackageLock Include="JetBrains.NuGet.Versioning" Version="7.0.20251002.162" />
<PackageLock Include="JetBrains.NuGet.Versioning" Version="7.0.20251126.165" />
<PackageLock Include="JetBrains.RdFramework" Version="2025.3.1" />
<PackageLock Include="Microsoft.NETCore.Platforms" Version="3.1.0" />
<PackageLock Include="Microsoft.NETCore.Targets" Version="1.1.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ItemGroup>
<PackageLock Include="FSharp.Core" Version="9.0.201" />
<PackageLock Include="JetBrains.Annotations" Version="2025.2.0" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2025.3.2" />
<PackageLock Include="JetBrains.FSharp.Compiler.Service" Version="2025.3.5.2" />
<PackageLock Include="JetBrains.Lifetimes" Version="2025.3.1" />
<PackageLock Include="JetBrains.RdFramework" Version="2025.3.1" />
<PackageLock Include="Microsoft.NETCore.Platforms" Version="3.1.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,19 @@ type FSharpLanguageLevelProjectProperty(lifetime, locks, projectPropertiesListen
let languageLevel = getLanguageLevelByToolsetVersion ()
VersionMapping(languageLevel, FSharpLanguageLevel.Preview)

// todo: more versions
let getLanguageLevelByCompilerVersion (fscVersion: Version): VersionMapping =
match fscVersion with
| Version (10, 1000, _) -> VersionMapping(FSharpLanguageLevel.FSharp47, FSharpLanguageLevel.FSharp50)
| Version (11, 0, _) -> VersionMapping(FSharpLanguageLevel.FSharp50, FSharpLanguageLevel.FSharp60)
| Version (12, minor, build) ->
if minor < 4 then VersionMapping(FSharpLanguageLevel.FSharp60, FSharpLanguageLevel.FSharp70)
elif minor >= 4 && minor <= 7 then VersionMapping(FSharpLanguageLevel.FSharp70, FSharpLanguageLevel.FSharp80)
elif minor = 8 && build < 200 then VersionMapping(FSharpLanguageLevel.FSharp80, FSharpLanguageLevel.FSharp90)
elif minor = 8 then VersionMapping(FSharpLanguageLevel.FSharp81, FSharpLanguageLevel.FSharp90)
elif minor >= 9 then VersionMapping(FSharpLanguageLevel.FSharp90, FSharpLanguageLevel.Preview)
else null
else
match minor with
| 8 when build < 200 -> VersionMapping(FSharpLanguageLevel.FSharp80, FSharpLanguageLevel.FSharp90)
| 8 -> VersionMapping(FSharpLanguageLevel.FSharp81, FSharpLanguageLevel.FSharp90)
| 9 -> VersionMapping(FSharpLanguageLevel.FSharp90, FSharpLanguageLevel.FSharp100)
| _ -> VersionMapping(FSharpLanguageLevel.FSharp100, FSharpLanguageLevel.Preview)
| _ -> null

let getCompilerVersion (fscPath: VirtualFileSystemPath) =
Expand Down Expand Up @@ -114,6 +115,7 @@ type FSharpLanguageLevelProjectProperty(lifetime, locks, projectPropertiesListen
FSharpLanguageLevel.FSharp81

| FSharpLanguageVersion.FSharp90 -> FSharpLanguageLevel.FSharp90
| FSharpLanguageVersion.FSharp100 -> FSharpLanguageLevel.FSharp100
| FSharpLanguageVersion.Default -> (getFscPath configuration |> getLanguageLevelByCompiler).DefaultVersion
| FSharpLanguageVersion.LatestMajor -> (getFscPath configuration |> getLanguageLevelByCompiler).LatestMajor
| FSharpLanguageVersion.Latest -> (getFscPath configuration |> getLanguageLevelByCompiler).LatestMinor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ open JetBrains.Util.DataStructures
type FcsModuleReaderCommonCache(lifetime: Lifetime, changeManager: ChangeManager) =
inherit AssemblyReaderShimChangeListenerBase(lifetime, changeManager)

// todo: is it ever cleared?
let assemblyTypeRefs = ConcurrentDictionary<IPsiModule, ConcurrentDictionary<IClrTypeName, ILTypeRef>>()

member this.GetOrCreateAssemblyTypeRefCache(targetModule: IPsiModule) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,9 @@ type ProjectFcsModuleReader(psiModule: IPsiModule, cache: FcsModuleReaderCommonC
timestamp <- DateTime.UtcNow
shim.Logger.Trace("New timestamp: {0}: {1}", path, timestamp)

member this.GetFcsIlType(t: IType) =
mkType t

interface IProjectFcsModuleReader with
member this.ILModuleDef =
FSharpAsyncUtil.CheckAndThrow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,33 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Util
open System.Collections.Generic
open FSharp.Compiler.Symbols
open JetBrains.Metadata.Reader.API
open JetBrains.Metadata.Reader.Impl
open JetBrains.ReSharper.Psi.ExtensionsAPI
open JetBrains.Util

[<Extension; Sealed; AbstractClass>]
[<Sealed; AbstractClass>]
type FcsAttributeUtil =
[<Extension>]
static member GetClrName(attr: FSharpAttribute) = attr.AttributeType.BasicQualifiedName
static member GetClrNameFullName(attr: FSharpAttribute) =
attr.AttributeType.BasicQualifiedName
|> Option.defaultValue SharedImplUtil.MISSING_DECLARATION_NAME

[<Extension>]
static member GetClrName(attr: FSharpAttribute) =
ClrTypeName(attr.GetClrNameFullName())

[<Extension>]
static member HasAttributeInstance(attrs: IList<FSharpAttribute>, clrName: string) =
attrs |> Seq.exists (fun a -> a.GetClrName() = clrName)
attrs |> Seq.exists (fun a -> a.GetClrNameFullName() = clrName)

[<Extension>]
static member GetAttributes(attrs: IList<FSharpAttribute>, clrName: string) =
let filteredAttributes = attrs |> Seq.filter (fun a -> a.GetClrName() = clrName)
let filteredAttributes = attrs |> Seq.filter (fun a -> a.GetClrNameFullName() = clrName)
filteredAttributes.AsIList()

[<Extension>]
static member TryFindAttribute(attrs: IList<FSharpAttribute>, clrName: string) =
attrs |> Seq.tryFind (fun a -> a.GetClrName() = clrName)
attrs |> Seq.tryFind (fun a -> a.GetClrNameFullName() = clrName)

[<Extension>]
static member HasAttributeInstance(attrs: IList<FSharpAttribute>, clrTypeName: IClrTypeName) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
[<AutoOpen; Extension>]
[<AutoOpen>]
module JetBrains.ReSharper.Plugins.FSharp.Util.FSharpPredefinedType

open System
open System.Collections.Generic
open FSharp.Compiler.Symbols
open JetBrains.Metadata.Reader.API
open JetBrains.Metadata.Reader.Impl
open JetBrains.ReSharper.Psi
Expand Down Expand Up @@ -132,41 +130,3 @@ let predefinedAbbreviations =
[<Extension; CompiledName("TryGetPredefinedAbbreviations")>]
let tryGetPredefinedAbbreviations(clrTypeName: IClrTypeName, names: outref<string[]>) =
predefinedAbbreviations.TryGetValue(clrTypeName, &names)


let isOption (fcsType: FSharpType) =
fcsType.ErasedType.BasicQualifiedName = fsOptionTypeName.FullName

let isValueOption (fcsType: FSharpType) =
fcsType.ErasedType.BasicQualifiedName = fsValueOptionTypeName.FullName

let isChoice (fcsType: FSharpType) =
fcsType.ErasedType.BasicQualifiedName.StartsWith("Microsoft.FSharp.Core.FSharpChoice`", StringComparison.Ordinal)

[<Extension; CompiledName("IsUnit")>]
let isUnit (fcsType: FSharpType) =
try fcsType.ErasedType.BasicQualifiedName = unitTypeName.FullName
with _ -> false

let isFSharpList (fcsType: FSharpType) =
if isNull fcsType then false else

let erasedType = fcsType.ErasedType
if not erasedType.HasTypeDefinition then false else

let fcsEntity = erasedType.TypeDefinition
if fcsEntity.IsArrayType then false else

fcsEntity.BasicQualifiedName = "Microsoft.FSharp.Collections.FSharpList`1"

[<Extension; CompiledName("IsNativePtr")>]
let isNativePtr (fcsType: FSharpType) =
try fcsType.ErasedType.BasicQualifiedName = StandardTypeNames.IntPtr
with _ -> false

let isReadOnly (fcsType: FSharpType) =
if fcsType.HasTypeDefinition && fcsType.TypeDefinition.IsArrayType then false else

let name = fcsType.ErasedType.BasicQualifiedName
startsWith "Microsoft.FSharp.Collections.FSharpList`" name ||
startsWith "System.String" name
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl
open JetBrains.ReSharper.Plugins.FSharp.Psi.PsiUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Psi.Util
open JetBrains.ReSharper.Plugins.FSharp.Util.FSharpPredefinedType
open JetBrains.ReSharper.Plugins.FSharp.Util.FSharpSymbolUtil
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.ExtensionsAPI
Expand Down Expand Up @@ -225,7 +224,7 @@ type LambdaAnalyzer() =

let typeIsReadOnly (expr: IFSharpExpression) =
let fcsType = expr.TryGetFcsType()
isNotNull fcsType && isReadOnly fcsType
isNotNull fcsType && (fcsType.IsFSharpList || fcsType.IsStringType)

let processor =
{ new IRecursiveElementProcessor with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ type FcsErrorsStageProcessBase(fsFile, daemonProcess) =
let node = nodeSelectionProvider.GetExpressionInRange(fsFile, range, false, null) |> getResultNode
if isNull node then
null
elif isUnit data.ExpectedType then
elif data.ExpectedType.IsUnitType then
createHighlightingFromNodeWithMessage UnitTypeExpectedError range error
else
createTypeMismatchHighlighting TypeEquationError range error
Expand Down Expand Up @@ -556,7 +556,7 @@ type FcsErrorsStageProcessBase(fsFile, daemonProcess) =
createHighlightingFromParentNodeWithMessage FieldNotContainedTypesDifferError range error

| Some (:? TypeMismatchDiagnosticExtendedData as data) ->
if isUnit data.ExpectedType then
if data.ExpectedType.IsUnitType then
createHighlightingFromMappedExpression getResultNode UnitTypeExpectedError range error else

createTypeMismatchHighlighting TypeConstraintMismatchError range error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl
open JetBrains.ReSharper.Plugins.FSharp.Psi.Util
open JetBrains.ReSharper.Plugins.FSharp.Settings
open JetBrains.ReSharper.Plugins.FSharp.Util.FSharpPredefinedType
open JetBrains.ReSharper.Plugins.FSharp.Util.FSharpSymbolUtil
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi.Tree

[<RequireQualifiedAccess>]
Expand Down Expand Up @@ -98,7 +97,7 @@ type PipeChainHighlightingProcess(fsFile, settings: IContextBoundSettingsStore,
| :? IDotLambdaExpr -> skipFunArgs exprType = pipeResultType
| _ ->
if not exprType.IsFunctionType || exprType.GenericArguments[1] <> pipeResultType then false else
if not (isUnit pipeResultType) then true else
if not (pipeResultType.IsUnitType) then true else

let invokedRefExpr =
match expr with
Expand All @@ -114,9 +113,8 @@ type PipeChainHighlightingProcess(fsFile, settings: IContextBoundSettingsStore,
| Some t ->
// We know that the result of the pipe is unit.
// We want to get the very last returned value and make sure that it is not generic, but strictly unit.
skipFunArgs t
|> isUnit
|> not
let t = skipFunArgs t
not t.IsUnitType
| None -> false

let adornExprs (exprs : (IReferenceExpr * ITreeNode * bool) ICollection) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Resolve
open JetBrains.ReSharper.Plugins.FSharp.Psi.Services.Util.FSharpCompletionUtil
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Plugins.FSharp.Psi.Util
open JetBrains.ReSharper.Plugins.FSharp.Util
open JetBrains.ReSharper.Psi
open JetBrains.ReSharper.Psi.Tree
open JetBrains.Util
Expand Down Expand Up @@ -151,7 +150,7 @@ type NameSuggestionFromTypeRule() =
| valueType -> Option.toList valueType.FcsType

let tryReplaceWithParameterBaseTypes (fcsType: FSharpType) =
if isUnit fcsType then [] else
if fcsType.IsUnitType then [] else
if not fcsType.IsGenericParameter then [fcsType] else

match fcsType.BaseType with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ type UnionCasePatternRule() =
match lookupItem.FcsSymbol with
| :? FSharpUnionCase as fcsUnionCase ->
let returnType = fcsUnionCase.ReturnType
if not (matchesType returnType || isFSharpList returnType) then
if not (matchesType returnType || returnType.IsFSharpList) then
let text = fcsUnionCase.Name
let fcsEntityInstance = FcsEntityInstance.create returnType
let item = createUnionCaseItem fcsEntityInstance returnType text fcsUnionCase false
Expand All @@ -282,8 +282,8 @@ type UnionCasePatternRule() =

match expectedType with
| None -> ()
| Some(fcsEntityInstance, fcsType, displayContext) ->
if isNull expectedTypeElement || isFSharpList fcsType then () else
| Some(fcsEntityInstance, fcsType, _) ->
if isNull expectedTypeElement || fcsType.IsFSharpList then () else

let fcsEntity = fcsEntityInstance.Entity
let typeName = expectedTypeElement.GetSourceName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ type FSharpDeclaredElementIconProvider() =
match declaredElement with
| :? IFSharpModule -> FSharpIcons.FSharpModule.Id

| :? IUnionCase as unionCase ->
| :? IFSharpUnionCase as unionCase ->
canApplyExtensions <- false
match unionCase.RepresentationAccessRights with
| AccessRights.PRIVATE -> privateCase
| AccessRights.INTERNAL -> internalCase
| _ -> PsiSymbolsThemedIcons.EnumMember.Id

| :? IRecordField as field ->
| :? IFSharpRecordField as field ->
canApplyExtensions <- false
if field.IsMutable then
match field.RepresentationAccessRights with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type FSharpLanguageService(languageType, constantValueService, cacheProvider: FS
member x.GetDefaultAccessType(declaredElement: IDeclaredElement) =
// todo: invocations, partial applications
match declaredElement with
| :? IUnionCase ->
| :? IFSharpUnionCase ->
ReferenceAccessType.OTHER

| :? IField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,12 @@ type FcsParameterInfoCandidateBase<'TSymbol, 'TParameter when 'TSymbol :> FSharp
let fcsParameterType = this.GetParamType(fcsParameter)
if not (this.IsOptionalParam(fcsParameter)) then fcsParameterType else

match tryGetAbbreviatedTypeEntity fcsParameterType with
| Some entity when entity.BasicQualifiedName = FSharpPredefinedType.fsOptionTypeName.FullName ->
if fcsParameterType.IsFSharpOption then
fcsParameterType.GenericArguments
|> Seq.tryExactlyOne
|> Option.defaultValue fcsParameterType
| _ -> fcsParameterType
else
fcsParameterType

text.Append(fcsParameterType.FormatLayout(displayContext) |> richText) |> ignore

Expand Down Expand Up @@ -444,16 +444,16 @@ type FcsActivePatternMfvParameterInfoCandidate(apc: FSharpActivePatternCase, mfv
match activePatternGroup.IsTotal with
| true when
names.Count > 1 && apc.Index < names.Count &&
apc.Index < mfvReturnType.GenericArguments.Count && FSharpPredefinedType.isChoice mfvReturnType ->
apc.Index < mfvReturnType.GenericArguments.Count && mfvReturnType.IsFSharpChoice ->
Some mfvReturnType.GenericArguments[apc.Index]

| false when
FSharpPredefinedType.isOption mfvReturnType ||
mfvReturnType.IsFSharpOption ||

FSharpPredefinedType.isValueOption mfvReturnType &&
mfvReturnType.IsFSharpValueOption &&
mfv.ReturnParameter.Attributes.HasAttributeInstance(FSharpPredefinedType.structAttrTypeName) ->
let optionArgType = mfvReturnType.GenericArguments[0]
if FSharpPredefinedType.isUnit optionArgType.ErasedType then None else Some optionArgType
if optionArgType.IsUnitType then None else Some optionArgType

| _ -> Some mfvReturnType

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ type FSharpTreeBuilderBase(lexer: ILexer, document: IDocument, warnDirectives: W

member x.AdvanceLexer() =
if nextDirectiveOffset <> -1 && x.CurrentOffset = nextDirectiveOffset then
while (isNotNull x.TokenType && x.TokenType.IsWhitespace) && not x.Eof do
x.Builder.AdvanceLexer() |> ignore

let (WarningDirectiveRange directiveRange) = warnDirectives.Head
setWarnDirectives warnDirectives.Tail

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ open JetBrains.Util

module ForPostfixTemplate =
let tryGetEnumerableTypeArg (contextExpr: IFSharpExpression) (fcsType: FSharpType) : FSharpType option =
let seenTypes = HashSet()
let seenTypes = HashSet<string>()

let rec loop (fcsType: FSharpType) =
let fcsType = FSharpSymbolUtil.getAbbreviatedType fcsType
Expand All @@ -44,7 +44,8 @@ module ForPostfixTemplate =
let entity = fcsType.TypeDefinition
if entity.IsArrayType then Some fcsType.GenericArguments[0] else

if not (seenTypes.Add(entity.BasicQualifiedName)) then None else
let qualifiedName = Option.defaultValue SharedImplUtil.MISSING_DECLARATION_NAME entity.BasicQualifiedName
if not (seenTypes.Add(qualifiedName)) then None else

fcsType.BaseType
|> Option.bind loop
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions

open JetBrains.ReSharper.Feature.Services.ContextActions
open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.DeclaredElement
open JetBrains.ReSharper.Plugins.FSharp.Psi
open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree
open JetBrains.ReSharper.Psi.Tree
open JetBrains.ReSharper.Resources.Shell
Expand All @@ -16,14 +16,14 @@ type ToMutableAction(dataProvider: FSharpContextActionDataProvider) =
let decl = dataProvider.GetSelectedElement<IRecordFieldDeclaration>()
if not (isValid decl && decl.GetNameRange().Contains(dataProvider.SelectedTreeRange)) then false else

let field = decl.DeclaredElement.As<IRecordField>()
let field = decl.DeclaredElement.As<IFSharpRecordField>()
isValid field && field.CanBeMutable && not field.IsMutable

override x.ExecutePsiTransaction _ =
let fieldDecl = dataProvider.GetSelectedElement<IRecordFieldDeclaration>()
use writeCookie = WriteLockCookie.Create(fieldDecl.IsPhysical())

let declaredElement = fieldDecl.DeclaredElement :?> IRecordField
let declaredElement = fieldDecl.DeclaredElement :?> IFSharpRecordField
declaredElement.SetIsMutable(true)


Expand All @@ -42,12 +42,12 @@ type ToImmutableFieldAction(dataProvider: FSharpContextActionDataProvider) =
let selectedRange = dataProvider.SelectedTreeRange
if not (nameRange.Contains(selectedRange) || mutableRange.Contains(selectedRange)) then false else

let field = decl.DeclaredElement.As<IRecordField>()
let field = decl.DeclaredElement.As<IFSharpRecordField>()
isValid field && field.IsMutable

override x.ExecutePsiTransaction _ =
let fieldDecl = dataProvider.GetSelectedElement<IRecordFieldDeclaration>()
use writeCookie = WriteLockCookie.Create(fieldDecl.IsPhysical())

let declaredElement = fieldDecl.DeclaredElement :?> IRecordField
let declaredElement = fieldDecl.DeclaredElement :?> IFSharpRecordField
declaredElement.SetIsMutable(false)
Loading
Loading