@@ -41,11 +41,13 @@ import qualified Development.IDE.GHC.ExactPrint as E
4141import Development.IDE.Plugin.CodeAction
4242import Development.IDE.Spans.AtPoint
4343import Development.IDE.Types.Location
44+ import GHC (isGoodSrcSpan )
4445import GHC.Iface.Ext.Types (HieAST (.. ),
4546 HieASTs (.. ),
4647 NodeOrigin (.. ),
4748 SourcedNodeInfo (.. ))
4849import GHC.Iface.Ext.Utils (generateReferencesMap )
50+ import qualified GHC.Types.Name.Occurrence as OccName
4951import HieDb.Query
5052import Ide.Plugin.Error
5153import Ide.Plugin.Properties
@@ -142,9 +144,18 @@ renameProvider state pluginId (RenameParams _prog (TextDocumentIdentifier uri) p
142144 -- Perform rename
143145 let newName = mkTcOcc $ T. unpack newNameText
144146 filesRefs = collectWith locToUri refs
147+
148+ -- GHC 9.8+ stores field labels and their selectors in different OccName
149+ -- namespaces, breaking equality checks. Expand to cover both variants.
150+ oldOccNames = HS. fromList $ concatMap (expandOcc . nameOccName) oldNames
151+ where
152+ expandOcc occ
153+ | occNameSpace occ == OccName. varName = [occ, mkOccNameFS (fieldName (occNameFS occ)) (occNameFS occ)]
154+ | isFieldNameSpace (occNameSpace occ) = [occ, mkOccNameFS OccName. varName (occNameFS occ)]
155+ | otherwise = [occ]
145156 getFileEdit (uri, locations) = do
146157 verTxtDocId <- liftIO $ runAction " rename: getVersionedTextDoc" state $ getVersionedTextDoc (TextDocumentIdentifier uri)
147- getSrcEdit state verTxtDocId (replaceRefs newName locations)
158+ getSrcEdit state verTxtDocId (replaceRefs newName locations oldOccNames )
148159 fileEdits <- mapM getFileEdit filesRefs
149160 pure $ InL $ fold fileEdits
150161
@@ -214,10 +225,10 @@ getSrcEdit state verTxtDocId updatePs = do
214225replaceRefs ::
215226 OccName ->
216227 HashSet Location ->
228+ HashSet OccName ->
217229 ParsedSource ->
218230 ParsedSource
219- replaceRefs newName refs = everywhere $
220- -- there has to be a better way...
231+ replaceRefs newName refs oldOccNames = everywhere $
221232 mkT (replaceLoc @ AnnListItem ) `extT`
222233 -- replaceLoc @AnnList `extT` -- not needed
223234 -- replaceLoc @AnnParen `extT` -- not needed
@@ -228,8 +239,11 @@ replaceRefs newName refs = everywhere $
228239 where
229240 replaceLoc :: forall an . LocatedAn an RdrName -> LocatedAn an RdrName
230241 replaceLoc (L srcSpan oldRdrName)
231- | isRef (locA srcSpan) = L srcSpan $ replace oldRdrName
242+ | isRef (locA srcSpan)
243+ , isTarget oldRdrName
244+ = L srcSpan $ replace oldRdrName
232245 replaceLoc lOldRdrName = lOldRdrName
246+
233247 replace :: RdrName -> RdrName
234248 replace (Qual modName _) = Qual modName newName
235249 replace _ = Unqual newName
@@ -239,6 +253,10 @@ replaceRefs newName refs = everywhere $
239253 Just loc -> loc `HS.member` refs
240254 Nothing -> False
241255
256+ -- Only replace RdrNames whose OccName matches a rename target, preventing
257+ -- co-located field selectors from being incorrectly renamed.
258+ isTarget :: RdrName -> Bool
259+ isTarget rdrName = rdrNameOcc rdrName `HS.member` oldOccNames
242260---------------------------------------------------------------------------------------------------
243261-- Reference finding
244262
@@ -250,38 +268,28 @@ refsAtName ::
250268 Name ->
251269 ExceptT PluginError m [Location ]
252270refsAtName state nfp targetName = do
253- -- Get local references from current file's HieAST
254- ast <- handleGetHieAst state nfp
255- let localRefs = nameLocs targetName ast
256-
257- -- Query HieDb for global matches (by OccName)
258- ShakeExtras {withHieDb} <- liftIO $ runAction " Rename.HieDb" state getShakeExtras
259- dbCandidates <- liftIO $ withHieDb $ \ hieDb ->
260- fmap (mapMaybe rowToLoc) $
261- case nameModule_maybe targetName of
262- Just mod -> findReferences hieDb True (nameOccName targetName) (Just $ moduleName mod ) (Just $ moduleUnit mod ) []
263- Nothing -> findReferences hieDb True (nameOccName targetName) Nothing Nothing []
264-
265- -- Filter candidates by exact Name identity
266- filteredDbRefs <- filterM (matchesExactName state targetName) dbCandidates
267- pure $ localRefs ++ filteredDbRefs
268-
269- matchesExactName ::
270- MonadIO m =>
271- IdeState ->
272- Name ->
273- Location ->
274- ExceptT PluginError m Bool
275- matchesExactName state targetName loc = do
276- (file, pos) <- locToFilePos loc
277- namesAtPos <- getNamesAtPos state file pos
278- pure $ targetName `elem` namesAtPos
279-
280- nameLocs :: Name -> HieAstResult -> [Location ]
281- nameLocs name (HAR _ _ rm _ _) =
282- concatMap (map (realSrcSpanToLocation . fst ))
283- (M. lookup (Right name) rm)
284-
271+ HAR {refMap} <- handleGetHieAst state nfp
272+
273+ let localRefs =
274+ case M. lookup (Right targetName) refMap of
275+ Nothing -> []
276+ Just spans -> [ realSrcSpanToLocation sp | (sp, _) <- spans]
277+
278+ let defLoc = nameSrcSpan targetName
279+ defLocations = case srcSpanToLocation defLoc of
280+ Just loc | isGoodSrcSpan defLoc -> [loc]
281+ _ -> []
282+
283+ -- Only query HieDb if it's a global name
284+ globalRefs <-
285+ case nameModule_maybe targetName of
286+ Nothing -> pure []
287+ Just mod -> do
288+ ShakeExtras {withHieDb} <- liftIO $ runAction " Rename.HieDb" state getShakeExtras
289+ liftIO $ withHieDb $ \ hieDb ->
290+ fmap (mapMaybe rowToLoc) $ findReferences hieDb True (nameOccName targetName) (Just $ moduleName mod ) (Just $ moduleUnit mod ) []
291+
292+ pure (defLocations ++ localRefs ++ globalRefs)
285293---------------------------------------------------------------------------------------------------
286294-- Util
287295
0 commit comments